{"record":{"id":"005d03986ccbde71","repo":"apache/seatunnel","slug":"python-source-thread-did-not-finish-within-ms","errorCode":null,"errorMessage":"Python source {} thread did not finish within {}ms while closing; it may keep running along with any descendant process it holds open","messagePattern":"Python source (.+?) thread did not finish within (.+?)ms while closing; it may keep running along with any descendant process it holds open","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"seatunnel-connectors-v2/connector-python/src/main/java/org/apache/seatunnel/connectors/seatunnel/python/source/PythonSourceReader.java","lineNumber":712,"sourceCode":"        if (closeRequested) {\n            thread.interrupt();\n        }\n        try {\n            thread.join(timeoutMillis);\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            if (closeException == null) {\n                return new IOException(\"Interrupted while closing python source \" + threadName, e);\n            }\n        }\n        if (thread.isAlive()) {\n            if (failOnTimeout && closeException == null) {\n                return new IOException(\"Timed out while closing python source \" + threadName);\n            }\n            // Not surfaced as a close failure (failOnTimeout=false, or an earlier join already\n            // produced closeException), but the thread outliving its bounded join is otherwise\n            // invisible: log it so a leaked thread or inherited descendant is observable.\n            LOG.warn(\n                    \"Python source {} thread did not finish within {}ms while closing; it may keep\"\n                            + \" running along with any descendant process it holds open\",\n                    threadName,\n                    timeoutMillis);\n        }\n        return closeException;\n    }\n\n    private synchronized void appendStderrLine(String line) {\n        if (recentStderrLines.size() == STDERR_HISTORY_LIMIT) {\n            recentStderrLines.removeFirst();\n        }\n        recentStderrLines.addLast(line);\n    }\n\n    private synchronized String formatRecentStderr() {\n        if (recentStderrLines.isEmpty()) {\n            return \"\";","sourceCodeStart":694,"sourceCodeEnd":730,"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#L694-L730","documentation":"During close(), the Python source reader joins its worker thread with a bounded timeout. If the thread does not finish in time and no earlier close failure was recorded, it logs this warning instead of failing the close — because the leaked thread (and any child process it keeps alive) would otherwise be invisible.","triggerScenarios":"joinThread is called from close(); streamCloser/reader thread does not terminate within timeoutMillis; failOnTimeout=false or an earlier join already produced closeException, so it is logged rather than thrown.","commonSituations":"Python script blocked on reading stdin or a long computation that ignores cancellation; descendant processes inherited from the Python process keeping the pipe open; very short close timeouts.","solutions":["Make the Python script respond to EOF/cancellation promptly (close streams, handle SIGTERM)","Increase the close timeout so legitimate slow shutdowns complete","Check the running script for child processes it spawns that keep handles open","If the warning recurs, terminate the leaked process at the OS level (kill the resolved executable pid)"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// ensure the script exits promptly on EOF\nfinal String scriptCheck = \"import sys; sys.stdin.readline(); sys.exit(0)\"; // verify behaves so under timeout","typeGuard":null,"tryCatchPattern":"try { reader.close(); } catch (IOException e) { /* closeException from join timeout */ log.warn(\"python reader close incomplete: {}\", e.getMessage()); }","preventionTips":["Write scripts that exit on stdin EOF and SIGTERM","Avoid spawning detached children from the Python process","Size the close timeout to expected script shutdown time","Monitor for leaked python processes in task managers"],"tags":["python","thread-leak","shutdown"],"backgroundTag":"request-timeout","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}