This is an automated email from the ASF dual-hosted git repository.

RaigorJiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git


The following commit(s) were added to refs/heads/master by this push:
     new 7a75e3931f6 Reset proxy backend executor across repeated 
ShardingSphereProxy lifecycles (#38665)
7a75e3931f6 is described below

commit 7a75e3931f6d404af7ee299c0112d997a0e22230
Author: Hengqian Ling <[email protected]>
AuthorDate: Sat May 9 10:11:18 2026 +0800

    Reset proxy backend executor across repeated ShardingSphereProxy lifecycles 
(#38665)
    
    * Reset proxy backend executor across repeated ShardingSphereProxy 
lifecycles
    
    * Introducing the Lifecycle
---
 .../backend/context/BackendExecutorContext.java    | 66 ++++++++++++++++++++--
 .../context/BackendExecutorContextTest.java        | 47 ++++++++++++++-
 .../proxy/initializer/BootstrapInitializer.java    |  2 +
 .../initializer/BootstrapInitializerTest.java      | 23 +++++++-
 .../proxy/frontend/ShardingSphereProxy.java        |  2 +-
 5 files changed, 131 insertions(+), 9 deletions(-)

diff --git 
a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/context/BackendExecutorContext.java
 
b/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/context/BackendExecutorContext.java
index d05ffb2c904..10578a8c85d 100644
--- 
a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/context/BackendExecutorContext.java
+++ 
b/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/context/BackendExecutorContext.java
@@ -18,7 +18,6 @@
 package org.apache.shardingsphere.proxy.backend.context;
 
 import lombok.AccessLevel;
-import lombok.Getter;
 import lombok.NoArgsConstructor;
 import org.apache.shardingsphere.infra.config.props.ConfigurationPropertyKey;
 import org.apache.shardingsphere.infra.executor.kernel.ExecutorEngine;
@@ -27,13 +26,13 @@ import 
org.apache.shardingsphere.infra.executor.kernel.ExecutorEngine;
  * Backend executor context.
  */
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
-@Getter
 public final class BackendExecutorContext {
     
     private static final BackendExecutorContext INSTANCE = new 
BackendExecutorContext();
     
-    private final ExecutorEngine executorEngine = 
ExecutorEngine.createExecutorEngineWithSize(
-            
ProxyContext.getInstance().getContextManager().getMetaDataContexts().getMetaData().getProps().<Integer>getValue(ConfigurationPropertyKey.KERNEL_EXECUTOR_SIZE));
+    private volatile ExecutorEngine executorEngine;
+    
+    private LifecycleState lifecycleState = LifecycleState.UNINITIALIZED;
     
     /**
      * Get executor context instance.
@@ -43,4 +42,63 @@ public final class BackendExecutorContext {
     public static BackendExecutorContext getInstance() {
         return INSTANCE;
     }
+    
+    /**
+     * Initialize backend executor context.
+     */
+    public synchronized void init() {
+        if (null != executorEngine) {
+            executorEngine.close();
+        }
+        executorEngine = ExecutorEngine.createExecutorEngineWithSize(
+                
ProxyContext.getInstance().getContextManager().getMetaDataContexts().getMetaData().getProps().<Integer>getValue(ConfigurationPropertyKey.KERNEL_EXECUTOR_SIZE));
+        lifecycleState = LifecycleState.RUNNING;
+    }
+    
+    /**
+     * Get executor engine.
+     *
+     * @return executor engine
+     * @throws IllegalStateException backend executor is unavailable in 
current lifecycle state
+     */
+    public synchronized ExecutorEngine getExecutorEngine() {
+        if (null == executorEngine) {
+            if (LifecycleState.CLOSED == lifecycleState) {
+                throw new IllegalStateException(String.format("Backend 
executor engine is unavailable in `%s` lifecycle state.", lifecycleState));
+            }
+            init();
+        }
+        if (LifecycleState.RUNNING != lifecycleState) {
+            throw new IllegalStateException(String.format("Backend executor 
engine is unavailable in `%s` lifecycle state.", lifecycleState));
+        }
+        return executorEngine;
+    }
+    
+    /**
+     * Close backend executor context.
+     */
+    public synchronized void close() {
+        if (null != executorEngine) {
+            executorEngine.close();
+            executorEngine = null;
+        }
+        lifecycleState = LifecycleState.UNINITIALIZED;
+    }
+    
+    /**
+     * Shutdown backend executor context.
+     */
+    public synchronized void shutdown() {
+        close();
+        lifecycleState = LifecycleState.CLOSED;
+    }
+    
+    private enum LifecycleState {
+        
+        UNINITIALIZED,
+        
+        RUNNING,
+        
+        CLOSED
+    }
 }
diff --git 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/context/BackendExecutorContextTest.java
 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/context/BackendExecutorContextTest.java
index b11d9e0e697..614b482e181 100644
--- 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/context/BackendExecutorContextTest.java
+++ 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/context/BackendExecutorContextTest.java
@@ -18,6 +18,7 @@
 package org.apache.shardingsphere.proxy.backend.context;
 
 import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
+import org.apache.shardingsphere.infra.executor.kernel.ExecutorEngine;
 import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
 import 
org.apache.shardingsphere.infra.metadata.database.resource.ResourceMetaData;
 import org.apache.shardingsphere.infra.metadata.database.rule.RuleMetaData;
@@ -26,14 +27,17 @@ import 
org.apache.shardingsphere.mode.manager.ContextManager;
 import org.apache.shardingsphere.mode.metadata.MetaDataContexts;
 import 
org.apache.shardingsphere.test.infra.framework.extension.mock.AutoMockExtension;
 import 
org.apache.shardingsphere.test.infra.framework.extension.mock.StaticMockSettings;
+import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 
 import java.util.Collections;
 import java.util.Properties;
 
-import static org.hamcrest.Matchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
@@ -42,11 +46,48 @@ import static org.mockito.Mockito.when;
 @StaticMockSettings(ProxyContext.class)
 class BackendExecutorContextTest {
     
+    @AfterEach
+    void tearDown() {
+        BackendExecutorContext.getInstance().close();
+    }
+    
+    @Test
+    void assertGetExecutorEngine() {
+        ContextManager contextManager = mockContextManager();
+        
when(ProxyContext.getInstance().getContextManager()).thenReturn(contextManager);
+        BackendExecutorContext.getInstance().init();
+        ExecutorEngine actual = 
BackendExecutorContext.getInstance().getExecutorEngine();
+        assertThat(actual, 
is(BackendExecutorContext.getInstance().getExecutorEngine()));
+    }
+    
+    @Test
+    void assertInit() {
+        ContextManager contextManager = mockContextManager();
+        
when(ProxyContext.getInstance().getContextManager()).thenReturn(contextManager);
+        BackendExecutorContext.getInstance().init();
+        ExecutorEngine actual = 
BackendExecutorContext.getInstance().getExecutorEngine();
+        BackendExecutorContext.getInstance().close();
+        BackendExecutorContext.getInstance().init();
+        assertThat(BackendExecutorContext.getInstance().getExecutorEngine(), 
is(not(actual)));
+    }
+    
+    @Test
+    void assertClose() {
+        ContextManager contextManager = mockContextManager();
+        
when(ProxyContext.getInstance().getContextManager()).thenReturn(contextManager);
+        BackendExecutorContext.getInstance().init();
+        BackendExecutorContext.getInstance().close();
+        ExecutorEngine actual = 
BackendExecutorContext.getInstance().getExecutorEngine();
+        assertThat(actual, 
is(BackendExecutorContext.getInstance().getExecutorEngine()));
+    }
+    
     @Test
-    void assertGetInstance() {
+    void assertShutdown() {
         ContextManager contextManager = mockContextManager();
         
when(ProxyContext.getInstance().getContextManager()).thenReturn(contextManager);
-        assertThat(BackendExecutorContext.getInstance().getExecutorEngine(), 
is(BackendExecutorContext.getInstance().getExecutorEngine()));
+        BackendExecutorContext.getInstance().init();
+        BackendExecutorContext.getInstance().shutdown();
+        assertThrows(IllegalStateException.class, () -> 
BackendExecutorContext.getInstance().getExecutorEngine());
     }
     
     private ContextManager mockContextManager() {
diff --git 
a/proxy/bootstrap/src/main/java/org/apache/shardingsphere/proxy/initializer/BootstrapInitializer.java
 
b/proxy/bootstrap/src/main/java/org/apache/shardingsphere/proxy/initializer/BootstrapInitializer.java
index 83d0892362c..7567cc43e5e 100644
--- 
a/proxy/bootstrap/src/main/java/org/apache/shardingsphere/proxy/initializer/BootstrapInitializer.java
+++ 
b/proxy/bootstrap/src/main/java/org/apache/shardingsphere/proxy/initializer/BootstrapInitializer.java
@@ -29,6 +29,7 @@ import 
org.apache.shardingsphere.mode.manager.builder.ContextManagerBuilderParam
 import org.apache.shardingsphere.proxy.backend.config.ProxyConfiguration;
 import org.apache.shardingsphere.proxy.backend.config.YamlProxyConfiguration;
 import 
org.apache.shardingsphere.proxy.backend.config.yaml.swapper.YamlProxyConfigurationSwapper;
+import org.apache.shardingsphere.proxy.backend.context.BackendExecutorContext;
 import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
 import org.apache.shardingsphere.proxy.version.ShardingSphereProxyVersion;
 
@@ -51,6 +52,7 @@ public final class BootstrapInitializer {
         ProxyConfiguration proxyConfig = new 
YamlProxyConfigurationSwapper().swap(yamlConfig);
         ContextManager contextManager = createContextManager(proxyConfig, 
modeConfig, port);
         ProxyContext.init(contextManager);
+        BackendExecutorContext.getInstance().init();
         ShardingSphereProxyVersion.setVersion(contextManager);
     }
     
diff --git 
a/proxy/bootstrap/src/test/java/org/apache/shardingsphere/proxy/initializer/BootstrapInitializerTest.java
 
b/proxy/bootstrap/src/test/java/org/apache/shardingsphere/proxy/initializer/BootstrapInitializerTest.java
index 97992487b7d..cb0435a514c 100644
--- 
a/proxy/bootstrap/src/test/java/org/apache/shardingsphere/proxy/initializer/BootstrapInitializerTest.java
+++ 
b/proxy/bootstrap/src/test/java/org/apache/shardingsphere/proxy/initializer/BootstrapInitializerTest.java
@@ -28,6 +28,7 @@ import 
org.apache.shardingsphere.mode.manager.builder.ContextManagerBuilderParam
 import org.apache.shardingsphere.proxy.backend.config.YamlProxyConfiguration;
 import 
org.apache.shardingsphere.proxy.backend.config.yaml.YamlProxyDatabaseConfiguration;
 import 
org.apache.shardingsphere.proxy.backend.config.yaml.YamlProxyServerConfiguration;
+import org.apache.shardingsphere.proxy.backend.context.BackendExecutorContext;
 import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
 import org.apache.shardingsphere.proxy.version.ShardingSphereProxyVersion;
 import 
org.apache.shardingsphere.test.infra.framework.extension.mock.AutoMockExtension;
@@ -52,11 +53,12 @@ import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 @ExtendWith(AutoMockExtension.class)
-@StaticMockSettings({ProxyContext.class, ShardingSphereProxyVersion.class})
+@StaticMockSettings({BackendExecutorContext.class, ProxyContext.class, 
ShardingSphereProxyVersion.class})
 class BootstrapInitializerTest {
     
     private final Map<Class<?>, Object> originalRegisteredServices = new 
HashMap<>(2, 1F);
@@ -90,6 +92,7 @@ class BootstrapInitializerTest {
         ArgumentCaptor<ContextManagerBuilderParameter> paramCaptor = 
ArgumentCaptor.forClass(ContextManagerBuilderParameter.class);
         verify(instanceMetaDataBuilder).build(3307, "");
         verify(contextManagerBuilder).build(paramCaptor.capture(), 
any(EventBusContext.class));
+        verify(BackendExecutorContext.getInstance()).init();
         ContextManagerBuilderParameter actualParameter = 
paramCaptor.getValue();
         ModeConfiguration actualModeConfig = 
actualParameter.getModeConfiguration();
         assertThat(actualModeConfig.getType(), is("Standalone"));
@@ -118,6 +121,7 @@ class BootstrapInitializerTest {
         ArgumentCaptor<ContextManagerBuilderParameter> paramCaptor = 
ArgumentCaptor.forClass(ContextManagerBuilderParameter.class);
         verify(instanceMetaDataBuilder).build(3307, "");
         verify(contextManagerBuilder).build(paramCaptor.capture(), 
any(EventBusContext.class));
+        verify(BackendExecutorContext.getInstance()).init();
         ContextManagerBuilderParameter actualParameter = 
paramCaptor.getValue();
         assertThat(actualParameter.getModeConfiguration().getType(), 
is("Cluster"));
         assertThat(actualParameter.getDatabaseConfigs().size(), is(1));
@@ -128,6 +132,23 @@ class BootstrapInitializerTest {
         assertThat(actualParameter.getInstanceMetaData(), 
is(instanceMetaData));
     }
     
+    @Test
+    void assertInitWithRepeatedLifecycle() throws SQLException, 
ReflectiveOperationException {
+        InstanceMetaDataBuilder instanceMetaDataBuilder = 
mock(InstanceMetaDataBuilder.class);
+        InstanceMetaData instanceMetaData = mock(InstanceMetaData.class);
+        registerSingletonService(InstanceMetaDataBuilder.class, 
instanceMetaDataBuilder);
+        ContextManagerBuilder contextManagerBuilder = 
mock(ContextManagerBuilder.class);
+        when(instanceMetaDataBuilder.getType()).thenReturn("Proxy");
+        when(instanceMetaDataBuilder.build(3307, 
"")).thenReturn(instanceMetaData);
+        when(contextManagerBuilder.isDefault()).thenReturn(true);
+        registerSingletonService(ContextManagerBuilder.class, 
contextManagerBuilder);
+        BootstrapInitializer bootstrapInitializer = new BootstrapInitializer();
+        bootstrapInitializer.init(createYamlProxyConfiguration(null), 3307);
+        BackendExecutorContext.getInstance().shutdown();
+        bootstrapInitializer.init(createYamlProxyConfiguration(null), 3307);
+        verify(BackendExecutorContext.getInstance(), times(2)).init();
+    }
+    
     private YamlProxyConfiguration createYamlProxyConfiguration(final 
YamlModeConfiguration modeConfig) {
         YamlProxyServerConfiguration serverConfig = new 
YamlProxyServerConfiguration();
         serverConfig.setMode(modeConfig);
diff --git 
a/proxy/frontend/core/src/main/java/org/apache/shardingsphere/proxy/frontend/ShardingSphereProxy.java
 
b/proxy/frontend/core/src/main/java/org/apache/shardingsphere/proxy/frontend/ShardingSphereProxy.java
index 0a10fc23060..0cfe853c5b1 100644
--- 
a/proxy/frontend/core/src/main/java/org/apache/shardingsphere/proxy/frontend/ShardingSphereProxy.java
+++ 
b/proxy/frontend/core/src/main/java/org/apache/shardingsphere/proxy/frontend/ShardingSphereProxy.java
@@ -168,7 +168,7 @@ public final class ShardingSphereProxy {
         }
         bossGroup.shutdownGracefully();
         workerGroup.shutdownGracefully();
-        BackendExecutorContext.getInstance().getExecutorEngine().close();
+        BackendExecutorContext.getInstance().shutdown();
         ProxyContext.getInstance().getContextManager().close();
         isClosed = true;
     }

Reply via email to