{"record":{"id":"e413289d0dbfc742","repo":"apache/shardingsphere","slug":"backend-executor-engine-is-unavailable-in-s-lif","errorCode":null,"errorMessage":"Backend executor engine is unavailable in `%s` lifecycle state.","messagePattern":"Backend executor engine is unavailable in `(.+?)` lifecycle state\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"critical","filePath":"proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/context/BackendExecutorContext.java","lineNumber":68,"sourceCode":"     * It may explicitly restore the context from the closed state for repeated proxy lifecycles in the same JVM.</p>\n     */\n    public synchronized void init() {\n        closeExecutorEngine();\n        executorEngine = ExecutorEngine.createExecutorEngineWithSize(\n                ProxyContext.getInstance().getContextManager().getMetaDataContexts().getMetaData().getProps().<Integer>getValue(ConfigurationPropertyKey.KERNEL_EXECUTOR_SIZE));\n        lifecycleState = LifecycleState.RUNNING;\n    }\n    \n    /**\n     * Get executor engine.\n     *\n     * @return executor engine\n     * @throws IllegalStateException backend executor is unavailable in current lifecycle state\n     */\n    public synchronized ExecutorEngine getExecutorEngine() {\n        if (null == executorEngine) {\n            if (LifecycleState.CLOSED == lifecycleState) {\n                throw new IllegalStateException(String.format(\"Backend executor engine is unavailable in `%s` lifecycle state.\", lifecycleState));\n            }\n            init();\n        }\n        if (LifecycleState.RUNNING != lifecycleState) {\n            throw new IllegalStateException(String.format(\"Backend executor engine is unavailable in `%s` lifecycle state.\", lifecycleState));\n        }\n        return executorEngine;\n    }\n    \n    /**\n     * Shutdown backend executor context.\n     *\n     * <p>After shutdown, request-side executor lookup is rejected until the next explicit lifecycle initialization.</p>\n     */\n    public synchronized void shutdown() {\n        closeExecutorEngine();\n        lifecycleState = LifecycleState.CLOSED;\n    }","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/apache/shardingsphere/blob/e952770a215630a3659c75d64369168cd3e26b82/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/context/BackendExecutorContext.java#L50-L86","documentation":"IllegalStateException thrown by BackendExecutorContext.getExecutorEngine() when the executor engine field is still null and the context lifecycle state is CLOSED. After shutdown() sets lifecycleState = CLOSED, any request-side lookup of the executor engine is rejected until an explicit re-initialization; this branch is the pre-init CLOSED check (line 68). It signals the proxy backend is being used after it was shut down.","triggerScenarios":"Calling BackendExecutorContext.getInstance().getExecutorEngine() after BackendExecutorContext.shutdown() has run (proxy graceful shutdown, XA/dist transaction driver reload, or a test that shuts down the context then issues a query). The null executorEngine + LifecycleState.CLOSED combination hits the first throw.","commonSituations":"Shutdown hooks racing in-flight queries during proxy stop/restart; unit tests that call shutdown() in @AfterEach but reuse the singleton context afterwards; embedded proxy restarted inside the same JVM without re-running init().","solutions":["Ensure no query/execution path runs after ProxyContext/BackendExecutorContext shutdown; drain in-flight requests before shutting down","If the proxy is intentionally restarted in-process, call the lifecycle init path again before issuing queries (getExecutorEngine re-inits only when state is not CLOSED)","In tests, reset or re-initialize BackendExecutorContext between test cases instead of using it after shutdown()"],"exampleFix":"// before\nBackendExecutorContext.getInstance().shutdown();\nExecutorEngine engine = BackendExecutorContext.getInstance().getExecutorEngine(); // IllegalStateException\n\n// after\nBackendExecutorContext.getInstance().shutdown();\n// restart lifecycle before next use\nBackendExecutorContext.getInstance().init();\nExecutorEngine engine = BackendExecutorContext.getInstance().getExecutorEngine();","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    ExecutorEngine engine = BackendExecutorContext.getInstance().getExecutorEngine();\n} catch (final IllegalStateException ex) {\n    // context is CLOSED: do not retry; re-init lifecycle or fail the request fast\n    throw new ServiceUnavailableException(\"Proxy executor is shut down\", ex);\n}","preventionTips":["Gate request handling on the proxy lifecycle (reject traffic during shutdown) so queries never race shutdown()","In tests, re-initialize BackendExecutorContext in @BeforeEach after any shutdown() in @AfterEach","Never cache ExecutorEngine references across restarts of the embedded proxy"],"tags":["lifecycle","concurrency","executor","proxy","shutdown"],"backgroundTag":null,"analyzedSha":"e952770a215630a3659c75d64369168cd3e26b82","analyzedAt":"2026-08-14T13:54:53.392Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}