{"record":{"id":"c1c9df71a117b9a1","repo":"apache/pulsar","slug":"interrupted-while-stopping-auto-ledger-re-replicat","errorCode":null,"errorMessage":"Interrupted while stopping auto ledger re-replication","messagePattern":"Interrupted while stopping auto ledger re-replication","errorType":"exception","errorClass":"ReplicationException.UnavailableException","httpStatus":null,"severity":"warning","filePath":"pulsar-metadata/src/main/java/org/apache/pulsar/metadata/bookkeeper/PulsarLedgerUnderreplicationManager.java","lineNumber":726,"sourceCode":"            throw new ReplicationException.UnavailableException(\"Interrupted while connecting metadata store\", ie);\n        }\n    }\n\n    @Override\n    public void disableLedgerReplication()\n            throws ReplicationException.UnavailableException {\n        log.debug(\"disableLedgerReplication()\");\n        try {\n            store.put(replicationDisablePath, \"\".getBytes(UTF_8), Optional.of(-1L))\n                    .get(BLOCKING_CALL_TIMEOUT, MILLISECONDS);\n            log.info(\"Auto ledger re-replication is disabled!\");\n        } catch (ExecutionException | TimeoutException ee) {\n            log.error().exception(ee).log(\"Exception while stopping auto ledger re-replication\");\n            throw new ReplicationException.UnavailableException(\n                    \"Exception while stopping auto ledger re-replication\", ee);\n        } catch (InterruptedException ie) {\n            Thread.currentThread().interrupt();\n            throw new ReplicationException.UnavailableException(\n                    \"Interrupted while stopping auto ledger re-replication\", ie);\n        }\n    }\n\n    @Override\n    public void enableLedgerReplication()\n            throws ReplicationException.UnavailableException {\n        log.debug(\"enableLedgerReplication()\");\n        try {\n            store.delete(replicationDisablePath, Optional.empty())\n                    .get(BLOCKING_CALL_TIMEOUT, MILLISECONDS);\n            log.info(\"Resuming automatic ledger re-replication\");\n        } catch (ExecutionException | TimeoutException ee) {\n            log.error().exception(ee).log(\"Exception while resuming ledger replication\");\n            throw new ReplicationException.UnavailableException(\n                    \"Exception while resuming auto ledger re-replication\", ee);\n        } catch (InterruptedException ie) {\n            Thread.currentThread().interrupt();","sourceCodeStart":708,"sourceCodeEnd":744,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-metadata/src/main/java/org/apache/pulsar/metadata/bookkeeper/PulsarLedgerUnderreplicationManager.java#L708-L744","documentation":"Thrown by disableLedgerReplication() when the thread blocked on the replication-disable marker put is interrupted. The interrupt flag is restored and the InterruptedException is wrapped as ReplicationException.UnavailableException. The disable marker may or may not have been written — re-check replication state afterwards.","triggerScenarios":"Interrupting the caller of disableLedgerReplication() while store.put(replicationDisablePath,...).get(...) is blocked, e.g. during admin-task cancellation or service shutdown.","commonSituations":"Admin CLI killed with SIGINT mid-command, admin HTTP request aborted by client disconnect handling that interrupts worker threads, or scheduled maintenance jobs cancelled at shutdown.","solutions":["After the interrupt, verify whether auto re-replication is actually disabled (isLedgerReplicationEnabled / check the disable node) before re-issuing.","Re-run disableLedgerReplication() if the marker was not persisted and disabling is still required.","Avoid interrupting admin operations that mutate metadata state; use cooperative cancellation.","Preserve interrupt status and surface the state ambiguity to the operator instead of silently retrying."],"exampleFix":"// before\nmanager.disableLedgerReplication();\n// after\ntry {\n    manager.disableLedgerReplication();\n} catch (ReplicationException.UnavailableException e) {\n    if (!manager.isLedgerReplicationEnabled()) {\n        return; // marker was written despite the interrupt\n    }\n    retryWithBackoff(() -> manager.disableLedgerReplication());\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"static boolean interruptedDuringDisable(ReplicationException.UnavailableException e) {\n    return e.getCause() instanceof InterruptedException;\n}","tryCatchPattern":"try {\n    manager.disableLedgerReplication();\n} catch (ReplicationException.UnavailableException e) {\n    if (interruptedDuringDisable(e)) {\n        Thread.currentThread().interrupt();\n        // re-check state: if (!manager.isLedgerReplicationEnabled()) marker landed\n        return;\n    }\n    throw e;\n}","preventionTips":["Do not cancel/interrupt admin operations that write metadata; wait for completion.","After any interrupt, verify replication state instead of assuming the disable failed or succeeded.","Keep disable/enable pairs on a single, non-interrupted worker thread.","Log correlation IDs so operators can reconcile state after interrupts."],"tags":["bookkeeper","interrupt","autorecovery","disable"],"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"}