{"record":{"id":"93ee5aba79d5f16e","repo":"apache/pulsar","slug":"interrupted-while-contacting-metadata-store","errorCode":null,"errorMessage":"Interrupted while contacting metadata store","messagePattern":"Interrupted while contacting metadata store","errorType":"exception","errorClass":"ReplicationException.UnavailableException","httpStatus":null,"severity":"warning","filePath":"pulsar-metadata/src/main/java/org/apache/pulsar/metadata/bookkeeper/PulsarLedgerUnderreplicationManager.java","lineNumber":485,"sourceCode":"                    }\n                }\n            }\n        } catch (ExecutionException ee) {\n            if (ee.getCause() instanceof MetadataStoreException.NotFoundException) {\n                // this is ok\n            } else if (ee.getCause() instanceof MetadataStoreException.BadVersionException) {\n                // if this is the case, some has marked the ledger\n                // for rereplication again. Leave the underreplicated\n                // znode in place, so the ledger is checked.\n            } else {\n                log.error().exception(ee).log(\"Error deleting underreplicated ledger node\");\n                throw new ReplicationException.UnavailableException(\"Error contacting metadata store\", ee);\n            }\n        } catch (TimeoutException ex) {\n            throw new ReplicationException.UnavailableException(\"Error contacting metadata store\", ex);\n        } catch (InterruptedException ie) {\n            Thread.currentThread().interrupt();\n            throw new ReplicationException.UnavailableException(\"Interrupted while contacting metadata store\", ie);\n        } finally {\n            releaseUnderreplicatedLedger(ledgerId);\n        }\n    }\n\n    /**\n     * Get a list of all the underreplicated ledgers which have been\n     * marked for rereplication, filtered by the predicate on the replicas list.\n     *\n     * <p>Replicas list of an underreplicated ledger is the list of the bookies which are part of\n     * the ensemble of this ledger and are currently unavailable/down.\n     *\n     * @param predicate filter to use while listing under replicated ledgers. 'null' if filtering is not required.\n     * @return an iterator which returns underreplicated ledgers.\n     */\n    @Override\n    public Iterator<UnderreplicatedLedger> listLedgersToRereplicate(final Predicate<List<String>> predicate) {\n        final Queue<String> queue = new LinkedList<>();","sourceCodeStart":467,"sourceCodeEnd":503,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-metadata/src/main/java/org/apache/pulsar/metadata/bookkeeper/PulsarLedgerUnderreplicationManager.java#L467-L503","documentation":"Thrown by markLedgerReplicated when the thread waiting on the blocking metadata-store future is interrupted; the InterruptedException cause carries the interruption. The method re-asserts the interrupt flag (Thread.currentThread().interrupt()) before wrapping, so interruption is not swallowed. This is ReplicationException.UnavailableException, i.e. the operation did not complete because the caller stopped waiting.","triggerScenarios":"Calling markLedgerReplicated(ledgerId) while the calling thread (typically the auditor's scheduled executor or a shutdown hook) is interrupted, e.g. during broker shutdown, executor.shutdownNow(), or a task cancelled while blocked in .get(BLOCKING_CALL_TIMEOUT) on store.delete/store.get.","commonSituations":"Broker/auditor shutdown racing with ledger replication completion; BookKeeper client closing its callback executors; tests cancelling futures; thread pools being torn down while rereplication work is in flight.","solutions":["Check whether the broker/auditor was shutting down at the time; if so this is expected and needs no fix.","Avoid interrupting the thread running markLedgerReplicated; let in-flight rereplication finish before calling shutdownNow().","Re-check the interrupt flag in your caller (it is preserved) and abort gracefully rather than retrying immediately.","If interruptions come from your own executor, use awaitTermination with a generous timeout after shutdown() before shutdownNow()."],"exampleFix":"// before: swallowing the exception and losing the interrupt flag\ncatch (ReplicationException.UnavailableException e) { /* ignore */ }\n\n// after: detect interruption and stop the loop\n} catch (ReplicationException.UnavailableException e) {\n    if (Thread.currentThread().isInterrupted()) {\n        log.info(\"Interrupted during markLedgerReplicated, stopping rereplication loop\");\n        return;\n    }\n    throw e;\n}","handlingStrategy":"try-catch","validationCode":"// Java: skip the call when the thread is already interrupted\nif (Thread.currentThread().isInterrupted()) {\n    return; // don't start blocking metadata-store work while interrupted\n}","typeGuard":null,"tryCatchPattern":"try {\n    manager.markLedgerReplicated(ledgerId);\n} catch (ReplicationException.UnavailableException e) {\n    if (Thread.currentThread().isInterrupted()) {\n        Thread.currentThread().interrupt(); // preserve flag, stop work\n        return;\n    }\n    throw e; // genuine store unavailability\n}","preventionTips":["Gracefully stop rereplication tasks before executor.shutdownNow()","Use awaitTermination with a sufficient timeout after shutdown()","Check Thread.interrupted() before entering blocking metadata-store calls","Never swallow InterruptedException — re-set the flag like the library does"],"tags":["interruption","threading","metadata-store","replication","shutdown"],"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"}