apache/shenyu · error · IllegalStateException

Timer already shutdown

Error message

Timer already shutdown

What it means

HierarchicalWheelTimer.start() throws IllegalStateException when the timer's single-thread task executor has already been shut down. The timer lazily starts its worker thread on first task add; once stop() has been called the executor is terminated and no further scheduling is permitted. This guards against silently accepting tasks into a dead timer.

Solutions

  1. Do not reuse the timer after shutdown; create a new HierarchicalWheelTimer instance for post-shutdown scheduling.
  2. Check timer state before adding tasks (expose or track an 'isShutdown' flag) and skip/re-route tasks.
  3. Fix lifecycle ordering: stop the timer only after all producers that schedule tasks have been stopped.
  4. If the shutdown was unintentional, audit shutdown-hook / @PreDestroy code paths that call the timer's stop method.

Example fix

// before
timer.stop();
timer.add(task); // IllegalStateException: Timer already shutdown
// after
if (!timer.isShutdown()) {
    timer.add(task);
} else {
    timer = new HierarchicalWheelTimer(...);
    timer.add(task);
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (timer.isShutdown()) { /* skip or recreate timer */ }

Type guard

boolean usable = timer != null && !timer.isShutdown();

Try / catch

try { timer.add(task); } catch (IllegalStateException e) { LOG.warn("timer stopped, dropping task", e); }

Prevention

When it happens

Trigger: Calling add(...) (or another method that invokes start()) on a HierarchicalWheelTimer after its shutdown/stop method has been executed.

Common situations: Application shutdown hooks stopping the timer while in-flight requests still try to schedule delayed tasks; plugin code caching a timer reference after the gateway context was reloaded; accidentally calling stop() then reusing the singleton timer instead of creating a new one.

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/shenyu@567142e072 (2026-09-12). Data as JSON: /api/errors/eddef58c9a5d5553. Report an issue: GitHub.

Appendix: source

Thrown at shenyu-common/src/main/java/org/apache/shenyu/common/timer/HierarchicalWheelTimer.java:139

            writeLock.lock();
            try {
                if (taskExecutor.isShutdown()) {
                    return;
                }
                while (Objects.nonNull(bucket)) {
                    timingWheel.advanceClock(bucket.getExpiration());
                    bucket.flush(this::addTimerTaskEntry);
                    bucket = delayQueue.poll();
                }
            } finally {
                writeLock.unlock();
            }
        }
    }

    private void start() {
        if (taskExecutor.isShutdown()) {
            throw new IllegalStateException("Timer already shutdown");
        }
        int state = WORKER_STATE_UPDATER.get(this);
        if (state == 0) {
            if (WORKER_STATE_UPDATER.compareAndSet(this, 0, 1)) {
                workerThread.start();
            }
        }
    }

    @Override
    public int size() {
        return taskCounter.get();
    }

    @Override
    public void shutdown() {
        writeLock.lock();
        try {

View on GitHub (pinned to 567142e072)