{"record":{"id":"b0f58adb1bda24cd","repo":"apache/seatunnel","slug":"interrupted-while-closing-python-source-reader","errorCode":null,"errorMessage":"Interrupted while closing python source reader","messagePattern":"Interrupted while closing python source reader","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"warning","filePath":"seatunnel-connectors-v2/connector-python/src/main/java/org/apache/seatunnel/connectors/seatunnel/python/source/PythonSourceReader.java","lineNumber":668,"sourceCode":"    }\n\n    /** Waits without abandoning cleanup when the close thread itself is interrupted. */\n    private boolean waitForLifecycleChange() {\n        try {\n            lifecycleLock.wait();\n            return false;\n        } catch (InterruptedException e) {\n            return true;\n        }\n    }\n\n    /** Restores an interrupt consumed while waiting for another close caller. */\n    private void restoreInterrupt(boolean interrupted) throws IOException {\n        if (!interrupted) {\n            return;\n        }\n        Thread.currentThread().interrupt();\n        throw new IOException(\"Interrupted while closing python source reader\");\n    }\n\n    private IOException joinThread(Thread thread, String threadName, IOException closeException) {\n        return joinThread(\n                thread,\n                threadName,\n                closeException,\n                TimeUnit.SECONDS.toMillis(PROCESS_DESTROY_TIMEOUT_SECONDS));\n    }\n\n    private IOException joinThread(\n            Thread thread, String threadName, IOException closeException, long timeoutMillis) {\n        return joinThread(thread, threadName, closeException, timeoutMillis, true);\n    }\n\n    private IOException joinThread(\n            Thread thread,\n            String threadName,","sourceCodeStart":650,"sourceCodeEnd":686,"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#L650-L686","documentation":"During close(), a thread that was interrupted while waiting for another close caller to finish (e.g. joining pump threads under lifecycleLock) restores its interrupt flag and throws this IOException. The library does this so the interrupt is not silently swallowed: the caller learns that close did not fully complete its waiting logic before being interrupted.","triggerScenarios":"Thread.interrupt() is delivered to a thread blocked waiting on another close caller inside close(); restoreInterrupt(boolean interrupted=true) is then called, re-interrupting the thread and throwing this IOException.","commonSituations":"Job cancellation or task shutdown interrupting the reader thread while it is closing; another component (e.g. engine teardown) interrupts the thread mid-close; double-close races where a second caller waits on the first.","solutions":["Treat it as cancellation: re-check the interrupt status and finish cleanup, since the interrupt flag has been restored","Retry close() if the underlying resources still need cleanup after handling the interrupt","Avoid interrupting SeaTunnel task threads during close unless cancellation is intended","Verify no watchdog/scheduler is spuriously interrupting threads during normal shutdown"],"exampleFix":"// before\nsourceReader.close();\n// after\ntry {\n    sourceReader.close();\n} catch (IOException e) {\n    if (Thread.currentThread().isInterrupted() && e.getMessage().contains(\"closing python source reader\")) {\n        LOG.warn(\"close interrupted; retrying cleanup\", e);\n        sourceReader.close();\n    } else {\n        throw e;\n    }\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    reader.close();\n} catch (IOException e) {\n    if (Thread.currentThread().isInterrupted()\n            && e.getMessage().contains(\"Interrupted while closing python source reader\")) {\n        LOG.warn(\"close was interrupted; interrupt flag restored, cleanup may be incomplete\");\n    } else {\n        throw e;\n    }\n}","preventionTips":["Do not interrupt task threads during normal shutdown unless cancellation is intended","Let close() complete before reusing or re-creating the reader","Check for watchdogs/schedulers issuing spurious interrupts during teardown","On catching this error, re-attempt cleanup if resources may still be open"],"tags":["python","interruption","lifecycle","close"],"backgroundTag":"thread-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"}