apache/pulsar · error · ManagedLedgerException

Timeout during managed ledger close

Error message

Timeout during managed ledger close

What it means

ManagedLedgerImpl.close() asynchronously waits (via CountDownLatch) for all cursors and the ledger to close. If the async close does not finish within AsyncOperationTimeoutSeconds, this ManagedLedgerException is thrown. It indicates a close operation hung, usually because an async ledger/cursor close callback never completed (e.g. BookKeeper client stalled or a cursor close callback was never invoked).

Source

Thrown at managed-ledger/src/main/java/org/apache/bookkeeper/mledger/impl/ManagedLedgerImpl.java:1640

        }
        final Result result = new Result();

        asyncClose(new CloseCallback() {
            @Override
            public void closeComplete(Object ctx) {
                counter.countDown();
            }

            @Override
            public void closeFailed(ManagedLedgerException exception, Object ctx) {
                result.exception = exception;
                counter.countDown();
            }

        }, null);

        if (!counter.await(AsyncOperationTimeoutSeconds, TimeUnit.SECONDS)) {
            throw new ManagedLedgerException("Timeout during managed ledger close");
        }

        if (result.exception != null) {
            log.error().exception(result.exception).log("Error closing managed ledger");
            throw result.exception;
        }
    }

    @Override
    public synchronized void asyncClose(final CloseCallback callback, final Object ctx) {
        State state = STATE_UPDATER.get(this);
        if (state.isFenced()) {
            cancelScheduledTasks();
            factory.close(this);
            callback.closeFailed(new ManagedLedgerFencedException(), ctx);
            return;
        } else if (state == State.Closed) {
            log.debug("Ignoring request to close a closed managed ledger");

View on GitHub (pinned to 820761864e)

Solutions

  1. Check BookKeeper and metadata-store (ZooKeeper) health; the close callback usually stalls because the underlying client is stuck
  2. Retry the close after connectivity is restored; the ledger remains closeable unless fenced
  3. If it recurs during shutdown, increase AsyncOperationTimeoutSeconds via the ServiceConfiguration to give slow closes more time
  4. Inspect broker logs just before the timeout for the first async operation error — the timeout masks the root cause

Example fix

// before
managedLedger.close(); // throws if BK is slow
// after
try {
    managedLedger.close();
} catch (ManagedLedgerException e) {
    log.warn("ML close timed out, scheduling retry", e);
    // retry close after reconnecting BookKeeper/metadata store
}
Defensive patterns

Strategy: try-catch

Validate before calling

// health check before close
if (!bkClientConnected || !zkSessionAlive) { scheduleRetryClose(); return; }

Try / catch

try {
    managedLedger.close();
} catch (ManagedLedgerException e) {
    log.warn("ML close timeout; check BookKeeper/metadata-store, then retry", e);
}

Prevention

When it happens

Trigger: Calling the synchronous ManagedLedger close() while an async ledger close or cursor close callback is delayed beyond AsyncOperationTimeoutSeconds (default 60s) — e.g. BookKeeper client disconnected, ZooKeeper/metadata store unresponsive, or a slow in-flight write preventing the ledger from being closed.

Common situations: Broker shutdown/restart while the metadata store or BookKeeper cluster is degraded; network partitions to bookies; ledger recovery stuck during broker failover; tests closing ledgers with a dead mock BK client.

Understand the failure class

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/b87846bb911840d2. Report an issue: GitHub.