{"record":{"id":"38073aad663df54c","repo":"apache/seatunnel","slug":"interrupted-while-draining-python-source-stdout-af","errorCode":null,"errorMessage":"Interrupted while draining Python source stdout after process exit","messagePattern":"Interrupted while draining Python source stdout after process exit","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"seatunnel-connectors-v2/connector-python/src/main/java/org/apache/seatunnel/connectors/seatunnel/python/source/PythonSourceReader.java","lineNumber":580,"sourceCode":"            if (System.nanoTime() >= stdoutCloseDeadlineNanos) {\n                throw inheritedStdoutTimeout();\n            }\n            return false;\n        }\n\n        long remainingNanos = stdoutCloseDeadlineNanos - System.nanoTime();\n        if (remainingNanos <= 0) {\n            throw inheritedStdoutTimeout();\n        }\n        long waitMillis =\n                Math.min(\n                        PROCESS_EXIT_CHECK_TIMEOUT_MILLIS,\n                        Math.max(1L, TimeUnit.NANOSECONDS.toMillis(remainingNanos)));\n        try {\n            stdoutPumpThread.join(waitMillis);\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            throw new IOException(\n                    \"Interrupted while draining Python source stdout after process exit\", e);\n        }\n\n        if (closeRequested) {\n            return false;\n        }\n        if (!stdoutLines.isEmpty()) {\n            if (System.nanoTime() >= stdoutCloseDeadlineNanos) {\n                throw inheritedStdoutTimeout();\n            }\n            return false;\n        }\n        if (isAlive(stdoutPumpThread)) {\n            if (System.nanoTime() >= stdoutCloseDeadlineNanos) {\n                throw inheritedStdoutTimeout();\n            }\n            return false;\n        }","sourceCodeStart":562,"sourceCodeEnd":598,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-python/src/main/java/org/apache/seatunnel/connectors/seatunnel/python/source/PythonSourceReader.java#L562-L598","documentation":"After the Python process exits, the reader joins the stdout pump thread with a deadline to drain any buffered output before finishing. If that join is interrupted, the InterruptedException is converted to this IOException so the failure surfaces through the normal source error path, with the interrupt flag restored first.","triggerScenarios":"Thread interruption during finishPumpsAfterProcessExit's awaitStdoutPumpAfterProcessExit — i.e. task cancellation, engine shutdown, or job failure arriving while the source is draining the child's remaining stdout.","commonSituations":"Job cancelled while the Python process just finished; cluster shutdown mid-checkpoint; a stop-with-savepoint triggering interrupts as the source winds down.","solutions":["If the job was intentionally stopped, this is expected teardown noise","Rerun the job; buffered data from the child is lost for the interrupted attempt","Avoid long-lived buffered output in the script (flush prints promptly) so drains finish fast"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    reader.close();\n} catch (IOException e) {\n    if (e.getMessage().contains(\"Interrupted while draining\")) {\n        // expected during cancellation; restore/check interrupt flag\n    }\n}","preventionTips":["Keep script output flushed so drains complete quickly","Don't interrupt tasks during normal finish; use proper cancellation APIs"],"tags":["interruption","process","shutdown"],"backgroundTag":"operation-interrupted","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}