{"record":{"id":"ba982265e6951ef4","repo":"apache/pulsar","slug":"interrupted-writing-cookie-for-bookie-bookieid","errorCode":null,"errorMessage":"Interrupted writing cookie for bookie ${bookieId}","messagePattern":"Interrupted writing cookie for bookie (.+?)","errorType":"exception","errorClass":"BookieException.MetadataStoreException","httpStatus":null,"severity":"warning","filePath":"pulsar-metadata/src/main/java/org/apache/pulsar/metadata/bookkeeper/PulsarRegistrationManager.java","lineNumber":241,"sourceCode":"    public void writeCookie(BookieId bookieId, Versioned<byte[]> cookieData) throws BookieException {\n        String path = this.cookiePath + \"/\" + bookieId;\n        try {\n            long version;\n            if (Version.NEW == cookieData.getVersion()) {\n                version = -1L;\n            } else {\n                if (!(cookieData.getVersion() instanceof LongVersion)) {\n                    throw new BookieException.BookieIllegalOpException(\n                            \"Invalid version type, expected it to be LongVersion\");\n                }\n                version = ((LongVersion) cookieData.getVersion()).getLongVersion();\n            }\n\n            store.put(path, cookieData.getValue(), Optional.of(version))\n                    .get(BLOCKING_CALL_TIMEOUT, MILLISECONDS);\n        } catch (InterruptedException ie) {\n            Thread.currentThread().interrupt();\n            throw new BookieException.MetadataStoreException(\"Interrupted writing cookie for bookie \" + bookieId, ie);\n        } catch (ExecutionException e) {\n            if (e.getCause() instanceof MetadataStoreException.BadVersionException) {\n                throw new BookieException.CookieExistException(bookieId.toString());\n            } else {\n                throw new BookieException.MetadataStoreException(\"Failed to write cookie for bookie \" + bookieId);\n            }\n        } catch (TimeoutException ex) {\n            throw new BookieException.MetadataStoreException(\"Failed to write cookie for bookie \" + bookieId, ex);\n        }\n    }\n\n    @Override\n    public Versioned<byte[]> readCookie(BookieId bookieId) throws BookieException {\n        String path = this.cookiePath + \"/\" + bookieId;\n        try {\n            Optional<GetResult> res = store.get(path).get(BLOCKING_CALL_TIMEOUT, MILLISECONDS);\n            if (!res.isPresent()) {\n                throw new BookieException.CookieNotFoundException(bookieId.toString());","sourceCodeStart":223,"sourceCodeEnd":259,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-metadata/src/main/java/org/apache/pulsar/metadata/bookkeeper/PulsarRegistrationManager.java#L223-L259","documentation":"writeCookie performs a blocking store.put(path, data, expectedVersion).get(timeout) on the asynchronous MetadataStore. If the waiting thread is interrupted, the manager restores the interrupt flag and rethrows the operation as BookieException.MetadataStoreException with the message 'Interrupted writing cookie for bookie <bookieId>'. It signals that the thread was asked to stop (shutdown, cancellation) rather than that the store rejected the write, so the cookie write's outcome is indeterminate.","triggerScenarios":"The thread blocked in writeCookie's .get(BLOCKING_CALL_TIMEOUT, MILLISECONDS) receives Thread.interrupt() — typically during bookie shutdown while writing/rewriting its cookie, or when an enclosing scheduler/executor cancels the registration task mid-write.","commonSituations":"Bookie process shutdown or failover while cookie registration is still in flight; a watchdog or test harness interrupting a hung metadata store (e.g. etcd/ZooKeeper connection stall) and thus unblocking the future wait; executor shutDownNow() cancelling startup threads.","solutions":["Treat it as a shutdown signal: let the BookieException propagate and complete the interrupted shutdown cleanly; do not swallow or loop-retry.","Check the interrupt status and stop the calling task rather than restarting cookie writes immediately.","If interruptions recur during normal operation, audit which component interrupts the bookie threads (executor shutdownNow, cancellation) and fix the lifecycle ordering so cookie registration finishes before shutdown.","After the restart completes, verify the cookie exists (readCookie) since the interrupted write may or may not have landed."],"exampleFix":"// before\ntry {\n    regManager.writeCookie(bookieId, cookie);\n} catch (BookieException e) {\n    log.warn(\"retrying\", e); // swallows interrupt, retries\n    regManager.writeCookie(bookieId, cookie);\n}\n\n// after\ntry {\n    regManager.writeCookie(bookieId, cookie);\n} catch (BookieException.MetadataStoreException e) {\n    if (Thread.currentThread().isInterrupted()) {\n        throw e; // shutdown in progress, do not retry\n    }\n    // handle genuine store failure\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    regManager.writeCookie(bookieId, cookie);\n} catch (BookieException.MetadataStoreException e) {\n    if (Thread.currentThread().isInterrupted()) {\n        // shutdown path: propagate and stop, do not retry\n        throw e;\n    }\n    throw e;\n}","preventionTips":["Complete cookie registration before initiating executor/process shutdown.","Avoid interrupting bookie startup threads during shutdownNow; use graceful shutdown that awaits in-flight registration tasks.","Keep metadata store responsive (healthy sessions, adequate timeouts) so blocking waits are short and less likely to be interrupted by watchdogs.","After an interrupted write, reconcile cookie state via readCookie before restarting."],"tags":["bookkeeper","metadata-store","cookie","interrupted","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-14T05:17:10.506Z"}