{"record":{"id":"eddef58c9a5d5553","repo":"apache/shenyu","slug":"timer-already-shutdown","errorCode":null,"errorMessage":"Timer already shutdown","messagePattern":"Timer already shutdown","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"shenyu-common/src/main/java/org/apache/shenyu/common/timer/HierarchicalWheelTimer.java","lineNumber":139,"sourceCode":"            writeLock.lock();\n            try {\n                if (taskExecutor.isShutdown()) {\n                    return;\n                }\n                while (Objects.nonNull(bucket)) {\n                    timingWheel.advanceClock(bucket.getExpiration());\n                    bucket.flush(this::addTimerTaskEntry);\n                    bucket = delayQueue.poll();\n                }\n            } finally {\n                writeLock.unlock();\n            }\n        }\n    }\n\n    private void start() {\n        if (taskExecutor.isShutdown()) {\n            throw new IllegalStateException(\"Timer already shutdown\");\n        }\n        int state = WORKER_STATE_UPDATER.get(this);\n        if (state == 0) {\n            if (WORKER_STATE_UPDATER.compareAndSet(this, 0, 1)) {\n                workerThread.start();\n            }\n        }\n    }\n\n    @Override\n    public int size() {\n        return taskCounter.get();\n    }\n\n    @Override\n    public void shutdown() {\n        writeLock.lock();\n        try {","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/apache/shenyu/blob/567142e07261b3e615ae8850b30f4421f455cc5d/shenyu-common/src/main/java/org/apache/shenyu/common/timer/HierarchicalWheelTimer.java#L121-L157","documentation":"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.","triggerScenarios":"Calling add(...) (or another method that invokes start()) on a HierarchicalWheelTimer after its shutdown/stop method has been executed.","commonSituations":"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.","solutions":["Do not reuse the timer after shutdown; create a new HierarchicalWheelTimer instance for post-shutdown scheduling.","Check timer state before adding tasks (expose or track an 'isShutdown' flag) and skip/re-route tasks.","Fix lifecycle ordering: stop the timer only after all producers that schedule tasks have been stopped.","If the shutdown was unintentional, audit shutdown-hook / @PreDestroy code paths that call the timer's stop method."],"exampleFix":"// before\ntimer.stop();\ntimer.add(task); // IllegalStateException: Timer already shutdown\n// after\nif (!timer.isShutdown()) {\n    timer.add(task);\n} else {\n    timer = new HierarchicalWheelTimer(...);\n    timer.add(task);\n}","handlingStrategy":"try-catch","validationCode":"if (timer.isShutdown()) { /* skip or recreate timer */ }","typeGuard":"boolean usable = timer != null && !timer.isShutdown();","tryCatchPattern":"try { timer.add(task); } catch (IllegalStateException e) { LOG.warn(\"timer stopped, dropping task\", e); }","preventionTips":["Track timer lifecycle centrally; no scheduling after stop()","Recreate the timer instead of reusing a shut-down instance","Order shutdown hooks: producers stop before timer stop","Add integration tests for shutdown-during-traffic scenarios"],"tags":["timer","lifecycle","illegal-state","concurrency"],"backgroundTag":"invalid-state-transition","analyzedSha":"567142e07261b3e615ae8850b30f4421f455cc5d","analyzedAt":"2026-09-12T10:08:21.293Z","contentChangedAt":"2026-09-12T10:08:21.293Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}