SonarSource/sonarqube · warning
Pool did not terminate
Error message
Pool {} did not terminate What it means
AbstractStoppableExecutorService.stop performs an orderly shutdown, waits 5s, calls shutdownNow, and waits another 5s; if the pool still has not terminated it logs this warning. It means some tasks ignored interruption and are still running while the component is being stopped — possible resource leaks or delayed shutdown.
Solutions
- Make worker tasks responsive to interruption: check Thread.currentThread().isInterrupted() and honor InterruptedException
- Add timeouts to blocking calls (HTTP client timeouts, socket timeouts, DB query timeouts)
- Check for non-daemon long-running tasks submitted to this pool and bound their work
- If it is a stuck third-party call, isolate it in a separate executor or use futures with get(timeout)
Example fix
// before
while (true) { process(next()); }
// after
while (!Thread.currentThread().isInterrupted()) {
process(next());
} Defensive patterns
Strategy: fallback
Try / catch
try {
pool.shutdown();
if (!pool.awaitTermination(5, TimeUnit.SECONDS)) {
pool.shutdownNow();
if (!pool.awaitTermination(5, TimeUnit.SECONDS)) {
log.warn("Pool {} did not terminate; tasks may be stuck", name);
}
}
} catch (InterruptedException ie) {
pool.shutdownNow();
Thread.currentThread().interrupt();
} Prevention
- Write tasks that check Thread.currentThread().isInterrupted() regularly
- Set timeouts on all blocking I/O performed inside pooled tasks
- Avoid submitting unbounded long-running loops to stoppable executors
When it happens
Trigger: stop() is called during server/component shutdown while a submitted Runnable/Callable ignores interrupts (long loop without interrupt checks) or blocks on non-interruptible I/O, so both awaitTermination(5s) calls return false.
Common situations: Blocking network/DB calls without timeout in worker tasks; infinite processing loops in tasks; many queued tasks that cannot finish within the grace period; shutdown during heavy load.
Related errors
- A plugin is storing excessively large data in the following…
- A version event already exists on analysis
- Ad-hoc rules export failed after processing
- An DevOps Platform setting with key
- An ' ' event with the same name already exists on analysis
AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09).
Data as JSON: /api/errors/a893fc2d3f9ace7d.
Report an issue: GitHub.
Appendix: source
Thrown at server/sonar-server-common/src/main/java/org/sonar/server/util/AbstractStoppableExecutorService.java:54
public abstract class AbstractStoppableExecutorService<D extends ExecutorService> implements StoppableExecutorService {
protected final D delegate;
public AbstractStoppableExecutorService(D delegate) {
this.delegate = delegate;
}
@Override
public void stop() {
// Disable new tasks from being submitted
delegate.shutdown();
try {
// Wait a while for existing tasks to terminate
if (!delegate.awaitTermination(5, TimeUnit.SECONDS)) {
// Cancel currently executing tasks
delegate.shutdownNow();
// Wait a while for tasks to respond to being canceled
if (!delegate.awaitTermination(5, TimeUnit.SECONDS)) {
LoggerFactory.getLogger(getClass()).warn("Pool {} did not terminate", getClass().getSimpleName());
}
}
} catch (InterruptedException ie) {
LoggerFactory.getLogger(getClass()).warn("Termination of pool {} failed", getClass().getSimpleName(), ie);
// (Re-)Cancel if current thread also interrupted
delegate.shutdownNow();
}
}
@Override
public void shutdown() {
delegate.shutdown();
}
@Override
public List<Runnable> shutdownNow() {
return delegate.shutdownNow();
}View on GitHub (pinned to 184c821202)