{"record":{"id":"e3a3d7158a24d00b","repo":"theonedev/onedev","slug":"java-lang-interruptedexception","errorCode":null,"errorMessage":"java.lang.InterruptedException","messagePattern":"java\\.lang\\.InterruptedException","errorType":"exception","errorClass":"RuntimeException","httpStatus":500,"severity":"warning","filePath":"server-core/src/main/java/io/onedev/server/rest/resource/BuildLogStreamResource.java","lineNumber":99,"sourceCode":"\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t};\n\t\t\tlogService.registerListener(logListener);\n\t\t\tsessionService.closeSession();\n\t\t\ttry {\n\t\t\t\tvar nextOffset = 0;\n\t\t\t\tLogSnippet snippet = logService.readLogSnippetReversely(loggingSupport, MAX_LOG_ENTRIES + 1);\n\t\t\t\tnextOffset = snippet.offset + snippet.entries.size();\n\t\t\t\tfor (var entry : snippet.entries)\n\t\t\t\t\twriteEntry(os, entry);\n\n\t\t\t\twhile (true) {\n\t\t\t\t\tsynchronized (os) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tos.wait(5000);\n\t\t\t\t\t\t} catch (InterruptedException e) {\n\t\t\t\t\t\t\tthrow new RuntimeException(e);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tvar entries = logService.readLogEntries(loggingSupport, nextOffset, 0);\n\t\t\t\t\t\tif (!entries.isEmpty()) {\n\t\t\t\t\t\t\tnextOffset += entries.size();\n\t\t\t\t\t\t\tfor (var entry : entries)\n\t\t\t\t\t\t\t\twriteEntry(os, entry);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tvar innerBuildStatus = sessionService.call(() -> buildService.load(buildId).getStatus());\n\t\t\t\t\t\t\tif (innerBuildStatus.isFinished()) {\n\t\t\t\t\t\t\t\twriteStatus(os, innerBuildStatus);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\twriteInt(os, 0);\n\t\t\t\t\t\t\t\tos.flush();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/rest/resource/BuildLogStreamResource.java#L81-L117","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: single long-lived stream\ncurl -f http://host/rest/builds/123/log -o build.log\n// after: retry with backoff on stream termination\nfor i in 1 2 3; do\n  curl -f --max-time 3600 http://host/rest/builds/123/log -o build.log && break\n  sleep $((i * 5))\ndone","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// retry streaming on interruption-caused termination\nfor (int attempt = 1; attempt <= 3; attempt++) {\n    try {\n        streamBuildLog(buildId, consumer);\n        break;\n    } catch (RuntimeException e) {\n        if (e.getCause() instanceof InterruptedException || isDisconnect(e)) {\n            sleep(attempt * 2000L);\n            continue;\n        }\n        throw e;\n    }\n}","preventionTips":["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."],"tags":["streaming","interruption","concurrency"],"backgroundTag":"request-timeout","analyzedSha":"d44925c47c37992c828ea673a5f9620539bc3ff2","analyzedAt":"2026-09-06T07:18:27.995Z","contentChangedAt":"2026-09-06T07:18:27.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}