{"record":{"id":"c65252159e0dde10","repo":"apache/pulsar","slug":"interrupted-while-resuming-auto-ledger-re-replicat","errorCode":null,"errorMessage":"Interrupted while resuming auto ledger re-replication","messagePattern":"Interrupted while resuming 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":745,"sourceCode":"                    \"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();\n            throw new ReplicationException.UnavailableException(\n                    \"Interrupted while resuming auto ledger re-replication\", ie);\n        }\n    }\n\n    @Override\n    public boolean isLedgerReplicationEnabled()\n            throws ReplicationException.UnavailableException {\n        log.debug(\"isLedgerReplicationEnabled()\");\n        try {\n            return !store.exists(replicationDisablePath)\n                    .get(BLOCKING_CALL_TIMEOUT, MILLISECONDS);\n        } catch (ExecutionException | TimeoutException ee) {\n            log.error().exception(ee).log(\"Error while checking the state of ledger re-replication\");\n            throw new ReplicationException.UnavailableException(\n                    \"Error contacting zookeeper\", ee);\n        } catch (InterruptedException ie) {\n            Thread.currentThread().interrupt();\n            throw new ReplicationException.UnavailableException(","sourceCodeStart":727,"sourceCodeEnd":763,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-metadata/src/main/java/org/apache/pulsar/metadata/bookkeeper/PulsarLedgerUnderreplicationManager.java#L727-L763","documentation":"Thrown by enableLedgerReplication() when the thread waiting on the metadata-store delete is interrupted before BLOCKING_CALL_TIMEOUT elapses. The method restores the interrupt flag (Thread.currentThread().interrupt()) and wraps the InterruptedException in ReplicationException.UnavailableException so callers of the BookKeeper underreplication API see a uniform checked type.","triggerScenarios":"The calling thread is interrupted (executor shutdown, broker shutdown, cancellation) while blocked in store.delete(...).get(timeout) inside enableLedgerReplication().","commonSituations":"Graceful broker shutdown cancels worker threads; an executor is shut down while an admin operation is in flight; a watchdog thread interrupts a stuck admin call.","solutions":["Re-check who interrupted the thread; on shutdown, abandon the operation and let it be re-run after restart.","Preserve interrupt status in your own code (the manager already restores it) and avoid swallowing it.","Retry the enable operation from a healthy, non-shutting-down thread if the interruption was unintended."],"exampleFix":"// before\nnew Thread(() -> auditor.enableLedgerReplication()).start(); // interrupted on shutdown\n// after\nexecutor.submit(() -> {\n    try {\n        auditor.enableLedgerReplication();\n    } catch (ReplicationException.UnavailableException e) {\n        if (Thread.currentThread().isInterrupted()) {\n            log.info(\"Enable replication cancelled by shutdown\");\n        }\n    }\n});","handlingStrategy":"try-catch","validationCode":"if (Thread.currentThread().isInterrupted()) {\n    throw new CancellationException(\"Thread already interrupted; skip enableLedgerReplication\");\n}","typeGuard":"boolean wasInterrupted(ReplicationException.UnavailableException e) {\n    return e.getCause() instanceof InterruptedException\n        || Thread.currentThread().isInterrupted();\n}","tryCatchPattern":"try {\n    urManager.enableLedgerReplication();\n} catch (ReplicationException.UnavailableException e) {\n    if (Thread.currentThread().isInterrupted()) {\n        // intentional shutdown: abort quietly\n        return;\n    }\n    throw e;\n}","preventionTips":["Only interrupt metadata-store worker threads during controlled shutdown.","Always check isInterrupted() after catching UnavailableException to classify the failure.","Reschedule pending enable operations after service restart instead of retrying in a dying thread."],"tags":["interruption","threading","bookkeeper-replication"],"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"}