theonedev/onedev · warning · RuntimeException
java.lang.InterruptedException
Error message
java.lang.InterruptedException
What it means
Inside downloadLog's streaming loop the thread waits on the output stream (os.wait(5000)) for new log entries. If the thread is interrupted while waiting, the InterruptedException is caught and rethrown wrapped in a RuntimeException. This happens when the client disconnects and the server cancels the streaming request, or the request times out and the container interrupts the worker thread.
Source
Thrown at server-core/src/main/java/io/onedev/server/rest/resource/BuildLogStreamResource.java:99
}
}
};
logService.registerListener(logListener);
sessionService.closeSession();
try {
var nextOffset = 0;
LogSnippet snippet = logService.readLogSnippetReversely(loggingSupport, MAX_LOG_ENTRIES + 1);
nextOffset = snippet.offset + snippet.entries.size();
for (var entry : snippet.entries)
writeEntry(os, entry);
while (true) {
synchronized (os) {
try {
os.wait(5000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
var entries = logService.readLogEntries(loggingSupport, nextOffset, 0);
if (!entries.isEmpty()) {
nextOffset += entries.size();
for (var entry : entries)
writeEntry(os, entry);
} else {
var innerBuildStatus = sessionService.call(() -> buildService.load(buildId).getStatus());
if (innerBuildStatus.isFinished()) {
writeStatus(os, innerBuildStatus);
break;
} else {
writeInt(os, 0);
os.flush();
}
}
}
}View on GitHub (pinned to d44925c47c)
Solutions
- Increase client/proxy read timeouts so the stream is not cut during quiet periods (e.g. nginx proxy_read_timeout).
- Wrap the streaming call client-side with reconnect logic — re-request the log from the last known offset.
- If it occurs during shutdown, it is expected; treat InterruptedException-wrapping RuntimeException as stream termination, not data loss.
- For very long builds, poll the completed log after the build finishes instead of holding a stream open.
Example fix
// before: single long-lived stream curl -f http://host/rest/builds/123/log -o build.log // after: retry with backoff on stream termination for i in 1 2 3; do curl -f --max-time 3600 http://host/rest/builds/123/log -o build.log && break sleep $((i * 5)) done
Defensive patterns
Strategy: retry
Try / catch
// retry streaming on interruption-caused termination
for (int attempt = 1; attempt <= 3; attempt++) {
try {
streamBuildLog(buildId, consumer);
break;
} catch (RuntimeException e) {
if (e.getCause() instanceof InterruptedException || isDisconnect(e)) {
sleep(attempt * 2000L);
continue;
}
throw e;
}
} Prevention
- Set generous read/idle timeouts on clients and reverse proxies for streaming endpoints.
- Expect stream termination on long-quiet builds and design consumers to reconnect.
- For finished builds, fetch the complete log instead of streaming.
- Monitor how long streams stay open; add keep-alive traffic if infrastructure demands it.
When it happens
Trigger: Client closes the connection mid-stream (timeout, Ctrl-C on curl, proxy cutoff) causing the servlet container to interrupt the streaming thread; server shutdown during an active log stream; long-lived streams exceeding platform idle timeouts.
Common situations: curl or a browser with a short read timeout on a quiet build (no new log entries for >5s intervals then disconnect); reverse proxies (nginx) closing idle upstream connections; job cancels/aborts interrupting log followers.
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
Related errors
AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06).
Data as JSON: /api/errors/e3a3d7158a24d00b.
Report an issue: GitHub.