{"record":{"id":"233b57e550c189b2","repo":"apache/druid","slug":"executor-is-shutdown-rejecting-task","errorCode":null,"errorMessage":"Executor is shutdown, rejecting task","messagePattern":"Executor is shutdown, rejecting task","errorType":"exception","errorClass":"RejectedExecutionException","httpStatus":null,"severity":"warning","filePath":"processing/src/main/java/org/apache/druid/java/util/common/concurrent/Execs.java","lineNumber":163,"sourceCode":"    if (capacity > 0) {\n      queue = new ArrayBlockingQueue<>(capacity);\n    } else {\n      queue = new SynchronousQueue<>();\n    }\n    return new ThreadPoolExecutor(\n        nThreads,\n        nThreads,\n        0L,\n        TimeUnit.MILLISECONDS,\n        queue,\n        makeThreadFactory(nameFormat, priority),\n        new RejectedExecutionHandler()\n        {\n          @Override\n          public void rejectedExecution(Runnable r, ThreadPoolExecutor executor)\n          {\n            if (executor.isShutdown()) {\n              throw new RejectedExecutionException(\"Executor is shutdown, rejecting task\");\n            }\n            try {\n              executor.getQueue().put(r);\n            }\n            catch (InterruptedException e) {\n              throw new RejectedExecutionException(\"Got Interrupted while adding to the Queue\", e);\n            }\n          }\n        }\n    );\n  }\n\n  public static ListeningExecutorService directExecutor()\n  {\n    return new DirectExecutorService();\n  }\n}\n","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/java/util/common/concurrent/Execs.java#L145-L181","documentation":"Execs' ThreadPoolExecutor uses a custom RejectedExecutionHandler that, when the executor is already shutdown, throws RejectedExecutionException('Executor is shutdown, rejecting task') instead of applying a fallback policy. Normally the handler would put the task on the queue; shutdown makes that pointless and unsafe, so it fails fast.","triggerScenarios":"A task is submitted (execute/submit) to a ThreadPoolExecutor created via Execs after shutdown()/shutdownNow(); the saturation handler detects executor.isShutdown() and throws rather than queuing.","commonSituations":"Shutdown races in ingestion/query services where workers keep submitting while the pool is being torn down; double-shutdown of a service followed by late submissions; tests that shut down executors in @After while async work still posts tasks.","solutions":["Order shutdown correctly: stop producers, await their completion, then shut down the executor","Wrap submissions in try/catch for RejectedExecutionException and handle teardown gracefully","Add an awaitTermination/graceful-stop step so in-flight submitters finish before shutdown","Use a lifecycle framework hook so executor shutdown always happens after dependent services stop"],"exampleFix":"// before\nservice.stop();\nworker.submit(work); // throws if worker's executor already stopped\n// after\nworker.stop();      // stop submitters first\nservice.stop();","handlingStrategy":"try-catch","validationCode":"if (executor.isShutdown()) {\n  throw new IllegalStateException(\"Executor already stopped; not submitting\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  executor.submit(task);\n} catch (RejectedExecutionException e) {\n  log.debug(\"Task rejected during shutdown: %s\", e.getMessage());\n}","preventionTips":["Await producer completion (countdown latches/futures) before calling shutdown()","Avoid double-shutdown paths that leave submitters racing the pool teardown","In tests, shut down executors after awaiting async task completion","Prefer unbounded or adequately sized queues when producers are bursty"],"tags":["concurrency","executor","rejected-execution"],"backgroundTag":"invalid-state-transition","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}