apache/druid · error · RejectedExecutionException
Service is closed.
Error message
Service is closed.
What it means
HttpPostEmitter queues events into batches and pushes them to a remote HTTP endpoint. awaitStarted() is called on every emit/flush path; it throws RejectedExecutionException('Service is closed.') when the emitter's emitting thread has been terminated (isTerminated() true), i.e. events are being submitted after close(). The library rejects work once the service lifecycle has ended rather than silently dropping events.
Source
Thrown at processing/src/main/java/org/apache/druid/java/util/emitter/core/HttpPostEmitter.java:208
if (!running) {
if (startLatch.getCount() == 0) {
throw new IllegalStateException("Already started.");
}
running = true;
startLatch.countDown();
emittingThread.start();
}
}
}
private void awaitStarted()
{
try {
if (!startLatch.await(1, TimeUnit.SECONDS)) {
throw new RejectedExecutionException("Service is not started.");
}
if (isTerminated()) {
throw new RejectedExecutionException("Service is closed.");
}
}
catch (InterruptedException e) {
log.debug("Interrupted waiting for start");
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
}
private boolean isTerminated()
{
return concurrentBatch.get() == null;
}
@Override
public void emit(Event event)
{
emitAndReturnBatch(event);View on GitHub (pinned to 9b90983fd2)
Solutions
- Ensure the emitter is started before use and not closed while events may still arrive: move emitter close() to the very end of shutdown sequencing.
- Guard emit calls with an isTerminated()/started check or wrap producers so they stop before the emitter closes.
- Catch RejectedExecutionException around emit/flush and drop or buffer events during shutdown.
- If this occurs at startup instead, verify Emitter.start() was called and completed within 1 second (startLatch await).
Example fix
// before emitter.close(); reportMetrics(emitter); // throws RejectedExecutionException // after reportMetrics(emitter); emitter.close();
Defensive patterns
Strategy: try-catch
Validate before calling
if (emitter instanceof HttpPostEmitter && ((HttpPostEmitter) emitter).isTerminated()) {
log.warn("Emitter closed; skipping emit");
return;
} Try / catch
try {
emitter.emit(event);
} catch (RejectedExecutionException e) {
log.debug(e, "Emitter closed, event dropped: %s", event);
} Prevention
- Close emitters last in shutdown order
- Stop all event producers before emitter.close()
- Start the emitter and await start completion before emitting
When it happens
Trigger: Calling emit(), flush(), or close()-time flush after HttpPostEmitter.close()/stop() has terminated the EmittingThread; a race where a producer thread emits while another thread closes the emitter; Lifecycle stop ordering where metrics emitters are shut down before components still emitting.
Common situations: Shutdown ordering bugs in Druid services (emitter stopped while real-time metrics still flowing); application code caching an Emitter reference after lifecycle.stop(); frameworks flushing telemetry during JVM shutdown after the emitter was closed.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Emit called unexpectedly before service start
- Service is not started.
- Service not started.
- can't stop.
- can't start
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/82b5bb945e03d9bb.
Report an issue: GitHub.