apache/druid · warning · RejectedExecutionException

Executor already shutdown

Error message

Executor already shutdown

What it means

DirectExecutorService.startTask() refuses new work once the executor has been shutdown, throwing RejectedExecutionException('Executor already shutdown'). DirectExecutorService runs tasks on the submitting thread under a lock, so after shutdown() any further execute() call is rejected. This mirrors Guava/ExecutorService rejection semantics.

Solutions

  1. Check executor.isShutdown() before submitting, or use an unshutdown owner for task submission
  2. Ensure shutdown() is called only after all producers have stopped submitting (join/await their completion first)
  3. Catch RejectedExecutionException around execute() and treat it as benign during teardown
  4. Restructure to use a lifecycle-managed executor (e.g. Druid's lifecycle scopes) so shutdown ordering is explicit

Example fix

// before
executor.execute(task);
// after
try {
  executor.execute(task);
} catch (RejectedExecutionException e) {
  // executor already shut down; drop or handle the task
}
Defensive patterns

Strategy: try-catch

Validate before calling

// guard before submitting
if (!executor.isShutdown()) {
  executor.execute(task);
}

Try / catch

try {
  executor.execute(task);
} catch (RejectedExecutionException e) {
  // expected during shutdown; drop task or route to a dead-letter handler
}

Prevention

When it happens

Trigger: Calling execute(task) (via startTask) on a DirectExecutorService after shutdown() or shutdownNow() has been invoked on it.

Common situations: Service lifecycle races: a service's stop()/shutdown() runs while another thread (e.g. a query callback or background submitter) still submits tasks; reusing a cached executor reference after its owner shut it down.

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


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/1442864c7c2b7af5. Report an issue: GitHub.

Appendix: source

Thrown at processing/src/main/java/org/apache/druid/java/util/common/concurrent/DirectExecutorService.java:151

        } else {
          long now = System.nanoTime();
          TimeUnit.NANOSECONDS.timedWait(lock, nanos);
          nanos -= System.nanoTime() - now; // subtract the actual time we waited
        }
      }
    }
  }

  /**
   * Checks if the executor has been shut down and increments the running task count.
   *
   * @throws RejectedExecutionException if the executor has been previously shutdown
   */
  private void startTask()
  {
    synchronized (lock) {
      if (shutdown) {
        throw new RejectedExecutionException("Executor already shutdown");
      }
      runningTasks++;
    }
  }

  /**
   * Decrements the running task count.
   */
  private void endTask()
  {
    synchronized (lock) {
      int numRunning = --runningTasks;
      if (numRunning == 0) {
        lock.notifyAll();
      }
    }
  }
}

View on GitHub (pinned to 9b90983fd2)