apache/pulsar · warning · org.apache.pulsar.client.impl.v5.PulsarClientException
Close interrupted
Error message
Close interrupted
What it means
ScalableQueueConsumer.close() waits on closeAsync().get(); if the waiting thread is interrupted, the interrupt flag is restored and a PulsarClientException with message "Close interrupted" is thrown. The close may still be in progress in the background — this error means the caller stopped waiting, not that close failed.
Source
Thrown at pulsar-client-v5/src/main/java/org/apache/pulsar/client/impl/v5/ScalableQueueConsumer.java:266
}
var future = segmentConsumers.get(id.segmentId());
if (future != null) {
future.thenAccept(c -> c.negativeAcknowledge(id.v4MessageId()));
}
}
@Override
public AsyncQueueConsumer<T> async() {
return asyncView;
}
@Override
public void close() throws PulsarClientException {
try {
closeAsync().get();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new PulsarClientException("Close interrupted", e);
} catch (ExecutionException e) {
throw new PulsarClientException(e.getCause());
}
}
// --- Async internals ---
@Override
public CompletableFuture<Message<T>> receiveAsync() {
return receiveQueue.receiveAsync();
}
@Override
public CompletableFuture<Void> closeAsync() {
closed = true;
receiveQueue.close();
dagWatch.close();
View on GitHub (pinned to 820761864e)
Solutions
- Let shutdown complete before interrupting worker threads (order shutdown: consumers first, executors last)
- Catch PulsarClientException and check that the interrupt flag is set to distinguish this case
- Prefer closeAsync() with orTimeout() over interrupt-based timeouts
- After catching, re-check consumer state and call closeAsync() again if needed
Example fix
// before executor.shutdownNow(); // interrupts in-flight close() consumer.close(); // after consumer.close(); // close consumers first executor.shutdownNow(); // then interrupt workers // or: consumer.closeAsync().get(30, TimeUnit.SECONDS);
Defensive patterns
Strategy: try-catch
Try / catch
try {
consumer.close();
} catch (PulsarClientException e) {
if ("Close interrupted".equals(e.getMessage())) {
log.warn("close interrupted; consumer may still be closing");
consumer.closeAsync(); // confirm/finish in background
}
} Prevention
- Order shutdown: consumers first, then interrupt threads
- Use timeouts (closeAsync().get(n, TimeUnit)) instead of interruption
- Never call shutdownNow() while close() is in flight
When it happens
Trigger: The thread calling close() is interrupted while blocked in closeAsync().get() — typically shutdown hooks, executor shutdownNow(), or future.cancel(true) interrupting the closing thread.
Common situations: Graceful shutdown racing with ExecutorService.shutdownNow(); timeouts implemented via thread interruption; application kill/SIGTERM handlers interrupting consumer-close threads.
Related errors
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/a228e209c72c4cc0.
Report an issue: GitHub.