{"record":{"id":"95031568165b7eb5","repo":"apache/seatunnel","slug":"interrupted-while-draining-python-source-process-o","errorCode":null,"errorMessage":"Interrupted while draining python source process output","messagePattern":"Interrupted while draining python source process output","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":617,"sourceCode":"        return true;\n    }\n\n    /** Creates the explicit protocol failure used when a child keeps the stdout pipe open. */\n    private static IOException inheritedStdoutTimeout() {\n        return new IOException(\n                \"Timed out waiting for Python source stdout to close after the process exited; ensure child processes do not inherit stdout\");\n    }\n\n    /** Gives a pump a short grace period to consume bytes already written by the direct child. */\n    private void waitForPumpDrain(Thread thread) throws IOException {\n        if (thread == null || !thread.isAlive()) {\n            return;\n        }\n        try {\n            thread.join(PROCESS_EXIT_CHECK_TIMEOUT_MILLIS);\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            throw new IOException(\"Interrupted while draining python source process output\", e);\n        }\n    }\n\n    private void checkPumpFailures() {\n        if (stdoutPumpFailure != null) {\n            throw new IllegalStateException(\n                    \"Failed to consume python source stdout\", stdoutPumpFailure);\n        }\n        if (stderrPumpFailure == null) {\n            return;\n        }\n        throw new IllegalStateException(\n                \"Failed to consume python source stderr\", stderrPumpFailure);\n    }\n\n    /** Registers one poll so close cannot return while rows or completion are still emitted. */\n    private boolean beginPoll() {\n        synchronized (lifecycleLock) {","sourceCodeStart":599,"sourceCodeEnd":635,"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#L599-L635","documentation":"waitForPumpDrain joins an output pump thread (stdout or stderr) for a bounded time after the Python process exits. If the join is interrupted, the reader restores the interrupt flag and throws this IOException, aborting the orderly drain of remaining child output.","triggerScenarios":"Interruption (task cancel/failure, engine shutdown) while finishPumpsAfterProcessExit waits on a pump thread via waitForPumpDrain.","commonSituations":"Job cancelled just as the Python process completed; pipeline failure elsewhere interrupts this task during its finish phase; repeated job restarts in a tight loop.","solutions":["Treat as expected during deliberate cancellation; rerun otherwise","Ensure the Python script flushes and closes stdout/stderr promptly on exit","Check for job-level failures causing cascading interrupts across tasks"],"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 python source process output\")) {\n        // teardown-time interrupt; verify it coincides with a deliberate cancel\n    }\n}","preventionTips":["Ensure script closes stdout/stderr promptly on exit","Avoid restart loops that cause cascading interrupts across tasks"],"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"}