15 days ago
i has web project it will build docker container then stat it container as web services. My docker file:
# ===== Build stage =====
FROM gradle:jdk21-alpine AS build
WORKDIR /home/gradle/project
COPY . .
RUN chmod +x ./gradlew \
&& ./gradlew bootJar --no-daemon
# ===== Runtime stage =====
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
EXPOSE 8080
COPY Asset ./Asset
COPY --from=build /home/gradle/project/build/libs/gradle-getting-started-1.0.jar app.jar
ENTRYPOINT ["java", "-Xms256m", "-Xmx768m", "-XX:+UseG1GC", "-XX:MaxGCPauseMillis=200", "-XX:+ExitOnOutOfMemoryError", "-jar", "app.jar"]
it work fine, but sometime it stuck at line:
RUN chmod +x ./gradlew \
&& ./gradlew bootJar --no-daemon
builder will download gradle lib and sometime it can not connect to server for dowload file and it stuck here forever.
few month ago it will return error timeout and i can click rebuild again now it just stuck there and i can not do anything. must Abort build and then recommit code again and pray for not stuck again!!
2 Replies
Status changed to Open Railway • 15 days ago
14 days ago
The root cause here is that Gradle has no network timeout configured by default in newer versions. When it tries to pull dependencies and the connection just hangs (not dropped, just silent), neither Gradle nor Docker knows to give up — so it waits forever. Older versions used to throw a timeout error on their own, that behavior changed.
Two things need to happen to fix this properly.
First, create a gradle.properties file in your project root if you don't already have one, and add these lines:
properties
systemProp.http.connectionTimeout=30000
systemProp.http.socketTimeout=30000
systemProp.https.connectionTimeout=30000
systemProp.https.socketTimeout=30000This tells Gradle to give up after 30 seconds if a server doesn't respond during connection, and another 30 if it connects but then goes silent. Without this, it just sits there indefinitely.
Second, restructure your Dockerfile to cache the dependency download layer separately from your source code. Right now, every single commit triggers a full re-download because your COPY . . and RUN gradle build are in the same layer. If anything in your source changes, Docker invalidates the whole thing and starts over from scratch — including hitting the network again.
Split it like this:
# ===== Build stage =====
FROM gradle:jdk21-alpine AS build
WORKDIR /home/gradle/project
COPY build.gradle settings.gradle ./
COPY gradle ./gradle
RUN timeout 300 ./gradlew dependencies --no-daemon \
-Dhttp.connectionTimeout=30000 \
-Dhttp.socketTimeout=30000
COPY . .
RUN chmod +x ./gradlew \
&& timeout 300 ./gradlew bootJar --no-daemon \
-Dhttp.connectionTimeout=30000 \
-Dhttp.socketTimeout=30000
# ===== Runtime stage =====
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
EXPOSE 8080
COPY Asset ./Asset
COPY --from=build /home/gradle/project/build/libs/gradle-getting-started-1.0.jar app.jar
ENTRYPOINT ["java", "-Xms256m", "-Xmx768m", "-XX:+UseG1GC", "-XX:MaxGCPauseMillis=200", "-XX:+ExitOnOutOfMemoryError", "-jar", "app.jar"]By copying only build.gradle and settings.gradle first and running the dependency download as its own step, Docker caches that layer independently. As long as your dependencies don't change, subsequent builds skip the download entirely and go straight to compiling your code.
The timeout 300 wrapper on both RUN steps is an extra safety net at the OS level — if Gradle somehow still hangs past the 30s timeout, Alpine's timeout command will forcibly kill the process after 5 minutes and return an actual error code. That means your rebuild button works again instead of you having to abort and pray.
First build after this change will still hit the network, but every build after that should be fast and stable unless you actually modify your dependencies.
3 days ago
let me try thank!