{"record":{"id":"00c50faec83f7363","repo":"apache/pulsar","slug":"commit-interrupted","errorCode":null,"errorMessage":"Commit interrupted","messagePattern":"Commit interrupted","errorType":"exception","errorClass":"PulsarClientException","httpStatus":null,"severity":"warning","filePath":"pulsar-client-v5/src/main/java/org/apache/pulsar/client/impl/v5/TransactionV5.java","lineNumber":51,"sourceCode":"    private final org.apache.pulsar.client.api.transaction.Transaction v4Transaction;\n    private final AsyncTransaction asyncView;\n\n    TransactionV5(org.apache.pulsar.client.api.transaction.Transaction v4Transaction) {\n        this.v4Transaction = v4Transaction;\n        this.asyncView = new AsyncView();\n    }\n\n    org.apache.pulsar.client.api.transaction.Transaction v4Transaction() {\n        return v4Transaction;\n    }\n\n    @Override\n    public void commit() throws PulsarClientException {\n        try {\n            v4Transaction.commit().get();\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            throw new PulsarClientException(\"Commit interrupted\", e);\n        } catch (ExecutionException e) {\n            Throwable cause = e.getCause() != null ? e.getCause() : e;\n            throw new PulsarClientException(cause.getMessage(), cause);\n        }\n    }\n\n    @Override\n    public void abort() throws PulsarClientException {\n        try {\n            v4Transaction.abort().get();\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            throw new PulsarClientException(\"Abort interrupted\", e);\n        } catch (ExecutionException e) {\n            Throwable cause = e.getCause() != null ? e.getCause() : e;\n            throw new PulsarClientException(cause.getMessage(), cause);\n        }\n    }","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-client-v5/src/main/java/org/apache/pulsar/client/impl/v5/TransactionV5.java#L33-L69","documentation":"TransactionV5.commit() blocks on the underlying v4 transaction's commit future. If the waiting thread is interrupted while blocked, the interrupt flag is restored and a PulsarClientException with the fixed message \"Commit interrupted\" is thrown. The transaction's actual commit outcome is unknown at that point — only the wait was cancelled.","triggerScenarios":"Calling commit() on a thread that gets interrupted while blocked in v4Transaction.commit().get() — e.g. executor shutdown, task cancellation, or another thread calling Thread.interrupt().","commonSituations":"Shutting down an application or executor while a transaction commit is pending; timeout-based task cancellation interrupting worker threads; request-handling threads interrupted by a web server during graceful shutdown.","solutions":["Do not interrupt threads waiting on commit(); await completion before shutdown, or use asyncView (async()) with a CompletableFuture handler instead of blocking commit().","Check the transaction's final state after recovery — the commit may have succeeded despite the interrupt; abort/retry idempotently as needed.","Ensure the thread's interrupt status handling is intentional: the library already restores the flag, so subsequent blocking calls will fail fast — re-create the transaction if needed."],"exampleFix":"// before\ntry (TransactionV5 txn = ... ) {\n    txn.commit(); // blocking; interrupted on shutdown\n}\n// after\nAsyncTransaction txn = ...;\ntxn.commitAsync()\n   .orTimeout(30, TimeUnit.SECONDS)\n   .whenComplete((r, ex) -> {\n       if (ex != null) log.warn(\"commit failed\", ex);\n   });","handlingStrategy":"try-catch","validationCode":"if (Thread.currentThread().isInterrupted()) {\n    throw new PulsarClientException(\"thread already interrupted; skipping commit\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    txn.commit();\n} catch (PulsarClientException e) {\n    if (\"Commit interrupted\".equals(e.getMessage())) {\n        // verify transaction state on coordinator before retrying\n    }\n}","preventionTips":["Use async() / commitAsync() instead of blocking commit() in executor-managed threads","Complete transactions before initiating shutdown","Avoid interrupting threads that hold open transactions","Treat an interrupted commit as outcome-unknown; reconcile state before retry"],"tags":["transaction","interrupt","concurrency","blocking"],"backgroundTag":"thread-interrupted","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}