You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hugegraph.apache.org by ji...@apache.org on 2026/10/08 15:34:57 UTC
(hugegraph) 07/15: fix(server): close request and graph resources
This is an automated email from the ASF dual-hosted git repository.
imbajin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hugegraph.git
commit 1af9589d97bad41e31fd4d68aca791b35616d101
Author: imbajin <ji...@apache.org>
AuthorDate: Thu Oct 8 20:31:40 2026 +0800
fix(server): close request and graph resources
- release backend leases at request and task completion
- preserve committed work and roll back unfinished writes
- cover authentication and graph transaction cleanup
---
.../apache/hugegraph/auth/HugeGraphAuthProxy.java | 9 +-
.../apache/hugegraph/server/ApplicationConfig.java | 16 ++-
.../hugegraph/backend/tx/GraphTransaction.java | 15 ++-
.../hugegraph/auth/BackendLeaseCleanupTest.java | 147 +++++++++++++++++++++
.../hugegraph/backend/tx/GraphTransactionTest.java | 18 +++
.../java/org/apache/hugegraph/core/AuthTest.java | 91 ++++++++++++-
.../org/apache/hugegraph/core/CoreTestSuite.java | 2 +
.../org/apache/hugegraph/unit/UnitTestSuite.java | 2 +
8 files changed, 290 insertions(+), 10 deletions(-)
diff --git a/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/auth/HugeGraphAuthProxy.java b/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/auth/HugeGraphAuthProxy.java
index 702abfe3b..9d23e8255 100644
--- a/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/auth/HugeGraphAuthProxy.java
+++ b/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/auth/HugeGraphAuthProxy.java
@@ -40,6 +40,7 @@ import java.util.function.Supplier;
import javax.security.sasl.AuthenticationException;
import org.apache.commons.configuration2.Configuration;
+import org.apache.hugegraph.HugeFactory;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.HugeGraphSupplier;
import org.apache.hugegraph.auth.HugeAuthenticator.RolePerm;
@@ -1303,7 +1304,13 @@ public final class HugeGraphAuthProxy implements HugeGraph {
try {
this.runner.run();
} finally {
- resetContext();
+ try {
+ HugeFactory.closeCurrentThreadTransactions();
+ } catch (Throwable e) {
+ LOG.error("Failed to close Gremlin worker transactions", e);
+ } finally {
+ resetContext();
+ }
}
}
}
diff --git a/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/server/ApplicationConfig.java b/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/server/ApplicationConfig.java
index 9bbed7f48..5cc3e0eb3 100644
--- a/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/server/ApplicationConfig.java
+++ b/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/server/ApplicationConfig.java
@@ -17,12 +17,14 @@
package org.apache.hugegraph.server;
+import org.apache.hugegraph.HugeFactory;
import org.apache.hugegraph.config.HugeConfig;
import org.apache.hugegraph.core.GraphManager;
import org.apache.hugegraph.define.WorkLoad;
import org.apache.hugegraph.event.EventHub;
import org.apache.hugegraph.exception.HugeException;
import org.apache.hugegraph.util.E;
+import org.apache.hugegraph.util.Log;
import org.apache.hugegraph.version.CoreVersion;
import org.apache.tinkerpop.gremlin.server.util.MetricManager;
import org.glassfish.hk2.api.Factory;
@@ -35,6 +37,7 @@ import org.glassfish.jersey.server.monitoring.ApplicationEvent;
import org.glassfish.jersey.server.monitoring.ApplicationEventListener;
import org.glassfish.jersey.server.monitoring.RequestEvent;
import org.glassfish.jersey.server.monitoring.RequestEventListener;
+import org.slf4j.Logger;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.jersey3.InstrumentedResourceMethodApplicationListener;
@@ -64,6 +67,9 @@ import jakarta.ws.rs.core.Context;
)
@ApplicationPath("/")
public class ApplicationConfig extends ResourceConfig {
+
+ private static final Logger LOG = Log.logger(ApplicationConfig.class);
+
@Context
private ServletConfig servletConfig;
@@ -195,7 +201,15 @@ public class ApplicationConfig extends ResourceConfig {
@Override
public RequestEventListener onRequest(RequestEvent event) {
- return null;
+ return request -> {
+ if (request.getType() == RequestEvent.Type.FINISHED) {
+ try {
+ HugeFactory.closeCurrentThreadTransactions();
+ } catch (RuntimeException e) {
+ LOG.error("Failed to release REST request transactions", e);
+ }
+ }
+ };
}
});
}
diff --git a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/tx/GraphTransaction.java b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/tx/GraphTransaction.java
index e807b74fb..70487f159 100644
--- a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/tx/GraphTransaction.java
+++ b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/tx/GraphTransaction.java
@@ -370,7 +370,12 @@ public class GraphTransaction extends IndexableTransaction {
Map<Id, HugeEdge> removedEdges) {
// Remove related edges of each vertex
for (HugeVertex v : removedVertices.values()) {
- if (!v.schemaLabel().existsLinkLabel()) {
+ // System edge labels may be absent from schema enumeration after
+ // request cleanup, so always scan auth/system vertex relations.
+ // OLAP shares its ID with a base vertex and must keep its original
+ // path rather than scan that base vertex's ordinary edges.
+ VertexLabel label = v.schemaLabel();
+ if ((!label.system() || label.olap()) && !label.existsLinkLabel()) {
continue;
}
// Query all edges of the vertex and remove them
@@ -638,7 +643,7 @@ public class GraphTransaction extends IndexableTransaction {
this.locksTable.lockReads(LockUtil.VERTEX_LABEL_DELETE,
vertex.schemaLabel().id());
this.locksTable.lockReads(LockUtil.INDEX_LABEL_DELETE,
- vertex.schemaLabel().indexLabels());
+ this.indexTx.indexLabelIds(vertex.schemaLabel()));
// Ensure vertex label still exists from vertex-construct to lock
this.graph().vertexLabel(vertex.schemaLabel().id());
/*
@@ -711,7 +716,7 @@ public class GraphTransaction extends IndexableTransaction {
// Override vertices in local `addedVertices`
this.addedVertices.remove(vertex.id());
// Force load vertex to ensure all properties are loaded (refer to #2181)
- if (!vertex.schemaLabel().indexLabels().isEmpty()) {
+ if (!this.indexTx.indexLabelIds(vertex.schemaLabel()).isEmpty()) {
vertex.forceLoad();
}
// Collect the removed vertex
@@ -905,7 +910,7 @@ public class GraphTransaction extends IndexableTransaction {
this.locksTable.lockReads(LockUtil.EDGE_LABEL_DELETE,
edge.schemaLabel().id());
this.locksTable.lockReads(LockUtil.INDEX_LABEL_DELETE,
- edge.schemaLabel().indexLabels());
+ this.indexTx.indexLabelIds(edge.schemaLabel()));
// Ensure edge label still exists from edge-construct to lock
this.graph().edgeLabel(edge.schemaLabel().id());
/*
@@ -1844,7 +1849,7 @@ public class GraphTransaction extends IndexableTransaction {
Id pkey = prop.propertyKey().id();
Set<Id> indexIds = new HashSet<>();
- for (Id il : schemaLabel.indexLabels()) {
+ for (Id il : this.indexTx.indexLabelIds(schemaLabel)) {
if (graph().indexLabel(il).indexFields().contains(pkey)) {
indexIds.add(il);
}
diff --git a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/auth/BackendLeaseCleanupTest.java b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/auth/BackendLeaseCleanupTest.java
new file mode 100644
index 000000000..9c8909d19
--- /dev/null
+++ b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/auth/BackendLeaseCleanupTest.java
@@ -0,0 +1,147 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hugegraph.auth;
+
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.hugegraph.HugeFactory;
+import org.apache.hugegraph.auth.HugeGraphAuthProxy.Context;
+import org.apache.hugegraph.auth.HugeGraphAuthProxy.ContextTask;
+import org.apache.hugegraph.backend.store.rocksdb.RocksDBSessions;
+import org.apache.hugegraph.backend.store.rocksdb.RocksDBStore;
+import org.apache.hugegraph.core.BaseCoreTest;
+import org.apache.hugegraph.testutil.Assert;
+import org.apache.hugegraph.testutil.Whitebox;
+import org.apache.tinkerpop.gremlin.structure.T;
+import org.apache.tinkerpop.gremlin.structure.Transaction;
+import org.junit.After;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
+
+public class BackendLeaseCleanupTest extends BaseCoreTest {
+
+ @Before
+ public void initSchema() {
+ graph().schema().vertexLabel("lifecycle").useCustomizeNumberId().create();
+ HugeFactory.closeCurrentThreadTransactions();
+ }
+
+ @After
+ public void cleanup() {
+ try {
+ HugeFactory.closeCurrentThreadTransactions();
+ } finally {
+ HugeGraphAuthProxy.resetContext();
+ }
+ }
+
+ @Test
+ public void testFailedTaskRollsBackDespiteCommitOnClose() {
+ AtomicInteger rollbackEvents = new AtomicInteger();
+ HugeGraphAuthProxy.setContext(Context.admin());
+ IllegalStateException failure = new IllegalStateException("task failed after writing");
+ ContextTask task = new ContextTask(() -> {
+ Transaction tx = graph().tx();
+ tx.onClose(Transaction.CLOSE_BEHAVIOR.COMMIT);
+ tx.onReadWrite(Transaction.READ_WRITE_BEHAVIOR.MANUAL);
+ tx.open();
+ tx.addTransactionListener(status -> rollbackEvents.incrementAndGet());
+ graph().addVertex(T.label, "lifecycle", T.id, 1L);
+ throw failure;
+ });
+ HugeGraphAuthProxy.resetContext();
+
+ Assert.assertSame(failure, Assert.assertThrows(IllegalStateException.class, task::run));
+ Assert.assertFalse(graph().tx().isOpen());
+ ThreadLocal<?> backend = Whitebox.getInternalState(graph().tx(), "transactions");
+ Assert.assertNull(backend.get());
+ Assert.assertNull(HugeGraphAuthProxy.getContext());
+ Assert.assertEquals(1, rollbackEvents.get());
+ // Reuse the worker thread: AUTO and default rollback must be restored.
+ Assert.assertEquals(0L, graph().traversal().V().count().next().longValue());
+ graph().addVertex(T.label, "lifecycle", T.id, 2L);
+ graph().tx().close();
+ Assert.assertEquals(0L, graph().traversal().V().count().next().longValue());
+ Assert.assertEquals(1, rollbackEvents.get());
+ }
+
+ @Test
+ public void testSuccessfulTaskKeepsExplicitCommitAndResetsThreadState() {
+ AtomicInteger commitEvents = new AtomicInteger();
+ HugeGraphAuthProxy.setContext(Context.admin());
+ ContextTask task = new ContextTask(() -> {
+ Transaction tx = graph().tx();
+ tx.onClose(Transaction.CLOSE_BEHAVIOR.COMMIT);
+ tx.onReadWrite(Transaction.READ_WRITE_BEHAVIOR.MANUAL);
+ tx.open();
+ tx.addTransactionListener(status -> commitEvents.incrementAndGet());
+ graph().addVertex(T.label, "lifecycle", T.id, 1L);
+ tx.commit();
+ });
+ HugeGraphAuthProxy.resetContext();
+
+ task.run();
+
+ Assert.assertFalse(graph().tx().isOpen());
+ ThreadLocal<?> backend = Whitebox.getInternalState(graph().tx(), "transactions");
+ Assert.assertNull(backend.get());
+ Assert.assertNull(HugeGraphAuthProxy.getContext());
+ Assert.assertEquals(1L, graph().traversal().V().count().next().longValue());
+ graph().addVertex(T.label, "lifecycle", T.id, 2L);
+ graph().tx().close();
+ Assert.assertEquals(1L, graph().traversal().V().count().next().longValue());
+ Assert.assertEquals(1, commitEvents.get());
+ }
+ @Test
+ public void testCommittedRocksDBWorkerReturnsBackendLeases() throws Exception {
+ Assume.assumeTrue("rocksdb".equals(graph().backend()));
+ ExecutorService worker = Executors.newSingleThreadExecutor();
+ try {
+ worker.submit(() -> {
+ try {
+ graph().addVertex(T.label, "lifecycle", T.id, 1L);
+ graph().tx().commit();
+ RocksDBStore store = Whitebox.getInternalState(params().graphTransaction(), "store");
+ Map<String, RocksDBSessions> databases = Whitebox.getInternalState(store, "dbs");
+ long threadId = Thread.currentThread().getId();
+ for (RocksDBSessions sessions : databases.values()) {
+ Map<Long, ?> leases = Whitebox.getInternalState(sessions, "sessions");
+ Assert.assertTrue(leases.containsKey(threadId));
+ }
+ HugeFactory.closeCurrentThreadTransactions();
+ for (RocksDBSessions sessions : databases.values()) {
+ Map<Long, ?> leases = Whitebox.getInternalState(sessions, "sessions");
+ Assert.assertFalse(leases.containsKey(threadId));
+ }
+ // Reuse this exact worker and confirm the committed row survives.
+ Assert.assertEquals(1L, graph().traversal().V().count().next().longValue());
+ } finally {
+ HugeFactory.closeCurrentThreadTransactions();
+ }
+ }).get(30, TimeUnit.SECONDS);
+ } finally {
+ worker.shutdownNow();
+ }
+ }
+
+}
diff --git a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/backend/tx/GraphTransactionTest.java b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/backend/tx/GraphTransactionTest.java
index a41ee5ffc..d5ed38aa4 100644
--- a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/backend/tx/GraphTransactionTest.java
+++ b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/backend/tx/GraphTransactionTest.java
@@ -19,6 +19,7 @@ package org.apache.hugegraph.backend.tx;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import org.apache.hugegraph.HugeFactory;
@@ -49,6 +50,23 @@ import org.mockito.Mockito;
public class GraphTransactionTest {
+ @Test
+ public void testOlapDeletionDoesNotScanBaseVertexEdges() {
+ GraphTransaction transaction = Mockito.mock(GraphTransaction.class, Mockito.CALLS_REAL_METHODS);
+ HugeVertex vertex = Mockito.mock(HugeVertex.class);
+ Mockito.when(vertex.schemaLabel()).thenReturn(VertexLabel.OLAP_VL);
+ Id id = IdGenerator.of(1L);
+ Mockito.when(vertex.id()).thenReturn(id);
+
+ // Preserve OLAP's original rejection before any ordinary edge scan.
+ IllegalStateException error = Assert.assertThrows(IllegalStateException.class, () -> {
+ transaction.prepareDeletions(Collections.singletonMap(id, vertex), Collections.emptyMap());
+ });
+ Assert.assertTrue(error.getMessage().startsWith("Graph is null of schema"));
+ Mockito.verify(transaction, Mockito.never()).queryEdgesFromBackend(Mockito.any());
+ Mockito.verify(transaction, Mockito.never()).doRemove(Mockito.any());
+ }
+
@Test
public void testBatchDecisionsRemainFixedAfterOriginChanges() {
ConditionQuery root = new ConditionQuery(HugeType.VERTEX);
diff --git a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/AuthTest.java b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/AuthTest.java
index 12afccd1f..66680e70c 100644
--- a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/AuthTest.java
+++ b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/AuthTest.java
@@ -27,7 +27,7 @@ import java.util.Objects;
import javax.security.sasl.AuthenticationException;
import org.apache.commons.collections.CollectionUtils;
-import org.apache.hugegraph.exception.HugeException;
+import org.apache.hugegraph.HugeFactory;
import org.apache.hugegraph.HugeGraph;
import org.apache.hugegraph.HugeGraphParams;
import org.apache.hugegraph.auth.AuthConstant;
@@ -45,6 +45,8 @@ import org.apache.hugegraph.auth.StandardAuthManager;
import org.apache.hugegraph.auth.TokenGenerator;
import org.apache.hugegraph.auth.UserWithRole;
import org.apache.hugegraph.backend.cache.Cache;
+import org.apache.hugegraph.exception.HugeException;
+import org.apache.hugegraph.exception.NotFoundException;
import org.apache.hugegraph.id.Id;
import org.apache.hugegraph.id.IdGenerator;
import org.apache.hugegraph.struct.schema.VertexLabel;
@@ -141,8 +143,7 @@ public class AuthTest extends BaseCoreTest {
}
//FIXME: support project in hstore
- boolean isHstore = Objects.equals("hstore", System.getProperty("backend")) ||
- (System.getProperty("backend") == null);
+ boolean isHstore = Objects.equals("hstore", graph.backend());
if (!isHstore) {
for (HugeProject project : authManager.listAllProject(-1)) {
@@ -1778,6 +1779,90 @@ public class AuthTest extends BaseCoreTest {
});
}
+ @Test
+ public void testProjectCleanupRepeatsWithoutBackendSystemProperty() {
+ Assume.assumeTrue("skip this test for hstore", !Objects.equals("hstore", graph().backend()));
+ String previous = System.getProperty("backend");
+ try {
+ System.clearProperty("backend");
+ for (int attempt = 0; attempt < 2; attempt++) {
+ this.testDeleteProjectAfterRequestCleanup();
+ this.clearAll();
+ Assert.assertEquals(0, graph().authManager().listAllProject(-1).size());
+ }
+ } finally {
+ if (previous == null) {
+ System.clearProperty("backend");
+ } else {
+ System.setProperty("backend", previous);
+ }
+ }
+ }
+
+ @Test
+ public void testDeleteProjectAfterRequestCleanup() {
+ Assume.assumeTrue("skip this test for hstore", !Objects.equals("hstore", graph().backend()));
+ AuthManager authManager = graph().authManager();
+ HugeProject project = makeProject("cleanup_project", "");
+ Id projectId = authManager.createProject(project);
+ HugeProject saved = authManager.getProject(projectId);
+ Id retainedId = authManager.createProject(makeProject("retained_project", ""));
+ HugeProject retained = authManager.getProject(retainedId);
+ Assert.assertEquals(3, authManager.listAccessByTarget(saved.targetId(), -1).size());
+ Id userId = authManager.createUser(makeUser("membership_user", "pass"));
+ authManager.createBelong(makeBelong(userId, saved.adminGroupId()));
+ Id retainedBelongId = authManager.createBelong(makeBelong(userId, retained.adminGroupId()));
+
+ // Match FINISHED cleanup between REST creation and deletion requests.
+ HugeFactory.closeCurrentThreadTransactions();
+ authManager.deleteProject(projectId);
+ HugeFactory.closeCurrentThreadTransactions();
+
+ Assert.assertEquals(0, authManager.listAccessByGroup(saved.adminGroupId(), -1).size());
+ Assert.assertEquals(0, authManager.listAccessByGroup(saved.opGroupId(), -1).size());
+ Assert.assertEquals(0, authManager.listAccessByTarget(saved.targetId(), -1).size());
+ Assert.assertEquals(3, authManager.listAccessByTarget(retained.targetId(), -1).size());
+ Assert.assertEquals(0, authManager.listBelongByGroup(saved.adminGroupId(), -1).size());
+ Assert.assertEquals(1, authManager.listBelongByUser(userId, -1).size());
+ Assert.assertEquals(retainedBelongId, authManager.getBelong(retainedBelongId).id());
+ Assert.assertEquals(userId, authManager.getUser(userId).id());
+ Assert.assertEquals(projectId, authManager.createProject(makeProject("cleanup_project", "")));
+ Assert.assertEquals(0, authManager.listBelongByGroup(saved.adminGroupId(), -1).size());
+ }
+
+ @Test
+ public void testDeleteUserWithRelationsAfterRequestCleanup() {
+ Assume.assumeTrue("skip this test for hstore", !Objects.equals("hstore", graph().backend()));
+ AuthManager authManager = graph().authManager();
+ Id deletedUser = authManager.createUser(makeUser("deleted_member", "pass"));
+ Id retainedUser = authManager.createUser(makeUser("retained_member", "pass"));
+ Id group = authManager.createGroup(makeGroup("shared_group"));
+ authManager.createBelong(makeBelong(deletedUser, group));
+ Id retainedBelong = authManager.createBelong(makeBelong(retainedUser, group));
+
+ HugeFactory.closeCurrentThreadTransactions();
+ authManager.deleteUser(deletedUser);
+ HugeFactory.closeCurrentThreadTransactions();
+
+ Assert.assertThrows(NotFoundException.class, () -> authManager.getUser(deletedUser));
+ Assert.assertEquals(0, authManager.listBelongByUser(deletedUser, -1).size());
+ Assert.assertEquals(1, authManager.listBelongByGroup(group, -1).size());
+ Assert.assertEquals(retainedBelong, authManager.getBelong(retainedBelong).id());
+ Assert.assertEquals(retainedUser, authManager.getUser(retainedUser).id());
+ }
+
+ @Test
+ public void testDeleteUserWithoutRelationsAfterRequestCleanup() {
+ Assume.assumeTrue("skip this test for hstore", !Objects.equals("hstore", graph().backend()));
+ AuthManager authManager = graph().authManager();
+ Id userId = authManager.createUser(makeUser("isolated_user", "pass"));
+ HugeFactory.closeCurrentThreadTransactions();
+ authManager.deleteUser(userId);
+ HugeFactory.closeCurrentThreadTransactions();
+ Assert.assertThrows(NotFoundException.class, () -> authManager.getUser(userId));
+ Assert.assertEquals(0, authManager.listBelongByUser(userId, -1).size());
+ }
+
@Test
public void testUpdateProject() {
Assume.assumeTrue("skip this test for hstore",
diff --git a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/CoreTestSuite.java b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/CoreTestSuite.java
index 5d33f9281..9b45f40a6 100644
--- a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/CoreTestSuite.java
+++ b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/CoreTestSuite.java
@@ -18,6 +18,7 @@
package org.apache.hugegraph.core;
import org.apache.hugegraph.HugeGraph;
+import org.apache.hugegraph.auth.BackendLeaseCleanupTest;
import org.apache.hugegraph.constant.ServiceConstant;
import org.apache.hugegraph.dist.RegisterUtil;
import org.apache.hugegraph.masterelection.GlobalMasterInfo;
@@ -34,6 +35,7 @@ import org.slf4j.Logger;
@RunWith(Suite.class)
@Suite.SuiteClasses({
+ BackendLeaseCleanupTest.class,
PropertyKeyCoreTest.class,
VertexLabelCoreTest.class,
EdgeLabelCoreTest.class,
diff --git a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/UnitTestSuite.java b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/UnitTestSuite.java
index 617440b66..0c9a0af01 100644
--- a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/UnitTestSuite.java
+++ b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/UnitTestSuite.java
@@ -44,6 +44,7 @@ import org.apache.hugegraph.unit.cache.CacheTest;
import org.apache.hugegraph.unit.cache.CachedGraphTransactionTest;
import org.apache.hugegraph.unit.cache.CachedSchemaTransactionTest;
import org.apache.hugegraph.unit.cache.RamTableTest;
+import org.apache.hugegraph.unit.cache.RequestCacheLifetimeTest;
import org.apache.hugegraph.unit.cmd.InitStoreConfigTest;
import org.apache.hugegraph.unit.config.GremlinConfigCompatibilityTest;
import org.apache.hugegraph.unit.config.GraphBinarySchemaCompatibilityTest;
@@ -148,6 +149,7 @@ import org.junit.runners.Suite;
MetaManagerSchemaCacheClearEventTest.class,
EtcdMetaDriverTest.class,
CachedGraphTransactionTest.class,
+ RequestCacheLifetimeTest.class,
CacheManagerTest.class,
RamTableTest.class,