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


The following commit(s) were added to refs/heads/master by this push:
     new 2d6380420 refactor(server): disable legacy master-worker scheduler 
logic (#3082)
2d6380420 is described below

commit 2d638042064b28dcbe6fe7cc39176c09d740fe5c
Author: Tsukilc <[email protected]>
AuthorDate: Wed Jul 8 13:03:56 2026 +0800

    refactor(server): disable legacy master-worker scheduler logic (#3082)
    
    This PR soft-disables the pre-PD master-worker task scheduling path while 
keeping old configs and task data upgrade-safe. Scheduler selection is now 
backend-driven: `hstore` uses `DistributedTaskScheduler`, and other backends 
use the local `StandardTaskScheduler`.
    
    ---------
    
    Co-authored-by: Himanshu Verma <[email protected]>
    Co-authored-by: imbajin <[email protected]>
---
 .../static/conf/hugegraph.properties.template      |   1 -
 .../org/apache/hugegraph/config/ServerOptions.java |   6 +-
 .../org/apache/hugegraph/core/GraphManager.java    |  89 ++--
 .../org/apache/hugegraph/StandardHugeGraph.java    |  33 +-
 .../org/apache/hugegraph/config/CoreOptions.java   |   8 +-
 .../hugegraph/masterelection/GlobalMasterInfo.java |   2 +-
 .../masterelection/StandardRoleListener.java       |   1 -
 .../hugegraph/task/DistributedTaskScheduler.java   | 303 ++++++++++---
 .../org/apache/hugegraph/task/HugeServerInfo.java  |   8 -
 .../java/org/apache/hugegraph/task/HugeTask.java   |   8 +
 .../apache/hugegraph/task/ServerInfoManager.java   | 342 +--------------
 .../hugegraph/task/StandardTaskScheduler.java      | 233 +++-------
 .../hugegraph/task/TaskAndResultScheduler.java     |  45 +-
 .../org/apache/hugegraph/task/TaskManager.java     | 135 +-----
 .../static/conf/graphs/hstore.properties.template  |   1 -
 .../static/conf/graphs/hugegraph.properties        |   1 -
 .../assembly/static/conf/rest-server.properties    |   3 -
 .../org/apache/hugegraph/core/MultiGraphsTest.java |  10 +-
 .../org/apache/hugegraph/core/TaskCoreTest.java    | 469 +++++++++++++++++++--
 .../org/apache/hugegraph/unit/UnitTestSuite.java   |   2 +
 .../hugegraph/unit/core/ServerInfoManagerTest.java |  32 ++
 .../unit/core/TaskSchedulerServerInfoTest.java     | 219 ++++++++++
 .../org/apache/hugegraph/options/CoreOptions.java  |   8 +-
 23 files changed, 1107 insertions(+), 852 deletions(-)

diff --git 
a/hugegraph-cluster-test/hugegraph-clustertest-dist/src/assembly/static/conf/hugegraph.properties.template
 
b/hugegraph-cluster-test/hugegraph-clustertest-dist/src/assembly/static/conf/hugegraph.properties.template
index 005031fe6..f97e36574 100644
--- 
a/hugegraph-cluster-test/hugegraph-clustertest-dist/src/assembly/static/conf/hugegraph.properties.template
+++ 
b/hugegraph-cluster-test/hugegraph-clustertest-dist/src/assembly/static/conf/hugegraph.properties.template
@@ -45,7 +45,6 @@ store=hugegraph
 pd.peers=$PD_PEERS_LIST$
 
 # task config
-task.scheduler_type=local
 task.schedule_period=10
 task.retry=0
 task.wait_timeout=10
diff --git 
a/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/config/ServerOptions.java
 
b/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/config/ServerOptions.java
index 278542854..1aed0434d 100644
--- 
a/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/config/ServerOptions.java
+++ 
b/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/config/ServerOptions.java
@@ -556,9 +556,9 @@ public class ServerOptions extends OptionHolder {
     public static final ConfigOption<String> SERVER_ID =
             new ConfigOption<>(
                     "server.id",
-                    "The id of hugegraph-server.",
-                    disallowEmpty(),
-                    "server-1"
+                    "The optional legacy id of hugegraph-server.",
+                    null,
+                    ""
             );
     public static final ConfigOption<String> SERVER_ROLE =
             new ConfigOption<>(
diff --git 
a/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/core/GraphManager.java
 
b/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/core/GraphManager.java
index 770e75cc7..ff0435964 100644
--- 
a/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/core/GraphManager.java
+++ 
b/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/core/GraphManager.java
@@ -58,7 +58,6 @@ import org.apache.hugegraph.auth.StandardAuthenticator;
 import org.apache.hugegraph.backend.BackendException;
 import org.apache.hugegraph.backend.cache.Cache;
 import org.apache.hugegraph.backend.cache.CacheManager;
-import org.apache.hugegraph.backend.id.IdGenerator;
 import org.apache.hugegraph.backend.store.AbstractBackendStoreProvider;
 import org.apache.hugegraph.backend.store.BackendStoreInfo;
 import org.apache.hugegraph.config.ConfigOption;
@@ -68,6 +67,7 @@ import org.apache.hugegraph.config.ServerOptions;
 import org.apache.hugegraph.config.TypedOption;
 import org.apache.hugegraph.event.EventHub;
 import org.apache.hugegraph.exception.ExistedException;
+import org.apache.hugegraph.exception.NotFoundException;
 import org.apache.hugegraph.exception.NotSupportException;
 import org.apache.hugegraph.io.HugeGraphSONModule;
 import org.apache.hugegraph.k8s.K8sDriver;
@@ -195,8 +195,6 @@ public final class GraphManager {
     public GraphManager(HugeConfig conf, EventHub hub) {
         LOG.info("Init graph manager");
         E.checkArgumentNotNull(conf, "The config can't be null");
-        String server = conf.get(ServerOptions.SERVER_ID);
-        String role = conf.get(ServerOptions.SERVER_ROLE);
 
         this.config = conf;
         this.url = conf.get(ServerOptions.REST_SERVER_URL);
@@ -206,10 +204,6 @@ public final class GraphManager {
                 conf.get(ServerOptions.SERVER_DEPLOY_IN_K8S);
         this.startIgnoreSingleGraphError = conf.get(
                 ServerOptions.SERVER_START_IGNORE_SINGLE_GRAPH_ERROR);
-        E.checkArgument(server != null && !server.isEmpty(),
-                        "The server name can't be null or empty");
-        E.checkArgument(role != null && !role.isEmpty(),
-                        "The server role can't be null or empty");
         this.graphsDir = conf.get(ServerOptions.GRAPHS);
         this.cluster = conf.get(ServerOptions.CLUSTER);
         this.graphSpaces = new ConcurrentHashMap<>();
@@ -1557,6 +1551,9 @@ public final class GraphManager {
         String raftGroupPeers = this.conf.get(ServerOptions.RAFT_GROUP_PEERS);
         config.addProperty(ServerOptions.RAFT_GROUP_PEERS.name(),
                            raftGroupPeers);
+
+        this.transferPdPeersConfig(config);
+
         this.transferRoleWorkerConfig(config);
 
         Graph graph = GraphFactory.open(config);
@@ -1575,6 +1572,19 @@ public final class GraphManager {
         }
     }
 
+    private void transferPdPeersConfig(HugeConfig config) {
+        if (config.containsKey(CoreOptions.PD_PEERS.name())) {
+            return;
+        }
+
+        String backend = config.get(CoreOptions.BACKEND);
+        boolean needPdPeers = this.conf.get(ServerOptions.USE_PD) ||
+                              StringUtils.equalsIgnoreCase("hstore", backend);
+        if (needPdPeers) {
+            config.addProperty(CoreOptions.PD_PEERS.name(), this.pdPeers);
+        }
+    }
+
     private void transferRoleWorkerConfig(HugeConfig config) {
         config.setProperty(RoleElectionOptions.NODE_EXTERNAL_URL.name(),
                            this.conf.get(ServerOptions.REST_SERVER_URL));
@@ -1635,23 +1645,21 @@ public final class GraphManager {
     }
 
     private void initNodeRole() {
-        String id = config.get(ServerOptions.SERVER_ID);
+        boolean enableRoleElection = config.get(
+                ServerOptions.ENABLE_SERVER_ROLE_ELECTION);
+        if (enableRoleElection) {
+            LOG.warn("The server.role_election option is deprecated and no " +
+                     "longer supported (removed with server_info persistence). 
" +
+                     "The configured server.role is still used for local node 
" +
+                     "role initialization. Set server.role_election=false to " 
+
+                     "suppress this warning.");
+        }
+
         String role = config.get(ServerOptions.SERVER_ROLE);
-        E.checkArgument(StringUtils.isNotEmpty(id),
-                        "The server name can't be null or empty");
         E.checkArgument(StringUtils.isNotEmpty(role),
                         "The server role can't be null or empty");
 
         NodeRole nodeRole = NodeRole.valueOf(role.toUpperCase());
-        boolean supportRoleElection = !nodeRole.computer() &&
-                                      this.supportRoleElection() &&
-                                      
config.get(ServerOptions.ENABLE_SERVER_ROLE_ELECTION);
-        if (supportRoleElection) {
-            // Init any server as Worker role, then do role election
-            nodeRole = NodeRole.WORKER;
-        }
-
-        this.globalNodeRoleInfo.initNodeId(IdGenerator.of(id));
         this.globalNodeRoleInfo.initNodeRole(nodeRole);
     }
 
@@ -1663,7 +1671,7 @@ public final class GraphManager {
         }
         if (!this.globalNodeRoleInfo.nodeRole().computer() && 
this.supportRoleElection() &&
             config.get(ServerOptions.ENABLE_SERVER_ROLE_ELECTION)) {
-            this.initRoleStateMachine();
+            LOG.info("Skip role state machine init (deprecated with 
server_info)");
         }
     }
 
@@ -1937,26 +1945,29 @@ public final class GraphManager {
     public HugeGraph graph(String graphSpace, String name) {
         String key = String.join(DELIMITER, graphSpace, name);
         Graph graph = this.graphs.get(key);
-        if (graph == null && isPDEnabled()) {
-            Map<String, Map<String, Object>> configs =
-                    this.metaManager.graphConfigs(graphSpace);
-            // If current server registered graph space is not DEFAULT, only 
load graph creation
-            // under registered graph space
-            if (!configs.containsKey(key) ||
-                (!"DEFAULT".equals(this.serviceGraphSpace) &&
-                 !graphSpace.equals(this.serviceGraphSpace))) {
-                return null;
+        if (graph == null) {
+            if (isPDEnabled()) {
+                Map<String, Map<String, Object>> configs =
+                        this.metaManager.graphConfigs(graphSpace);
+                // If current server registered graph space is not DEFAULT, 
only load graph creation
+                // under registered graph space
+                if (!configs.containsKey(key) ||
+                    (!"DEFAULT".equals(this.serviceGraphSpace) &&
+                     !graphSpace.equals(this.serviceGraphSpace))) {
+                    return null;
+                }
+                Map<String, Object> config = configs.get(key);
+                String creator = String.valueOf(config.get("creator"));
+                Date createTime = parseDate(config.get("create_time"));
+                Date updateTime = parseDate(config.get("update_time"));
+                HugeGraph graph1 = this.createGraph(graphSpace, name,
+                                                    creator, config, false);
+                graph1.createTime(createTime);
+                graph1.updateTime(updateTime);
+                this.graphs.put(key, graph1);
+                return graph1;
             }
-            Map<String, Object> config = configs.get(key);
-            String creator = String.valueOf(config.get("creator"));
-            Date createTime = parseDate(config.get("create_time"));
-            Date updateTime = parseDate(config.get("update_time"));
-            HugeGraph graph1 = this.createGraph(graphSpace, name,
-                                                creator, config, false);
-            graph1.createTime(createTime);
-            graph1.updateTime(updateTime);
-            this.graphs.put(key, graph1);
-            return graph1;
+            throw new NotFoundException(String.format("Graph '%s' does not 
exist", name));
         } else if (graph instanceof HugeGraph) {
             return (HugeGraph) graph;
         }
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/StandardHugeGraph.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/StandardHugeGraph.java
index aaacb799c..6f66b4b8a 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/StandardHugeGraph.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/StandardHugeGraph.java
@@ -177,7 +177,6 @@ public class StandardHugeGraph implements HugeGraph {
     private final BackendStoreProvider storeProvider;
     private final TinkerPopTransaction tx;
     private final RamTable ramtable;
-    private final String schedulerType;
     private volatile boolean started;
     private volatile boolean closed;
     private volatile GraphMode mode;
@@ -226,11 +225,18 @@ public class StandardHugeGraph implements HugeGraph {
 
         this.taskManager = TaskManager.instance();
         this.name = config.get(CoreOptions.STORE);
+
+        // Keep old config files upgrade-safe while ignoring the legacy 
scheduler.
+        if (config.containsKey("task.scheduler_type")) {
+            LOG.warn("Config key 'task.scheduler_type' is deprecated and " +
+                     "ignored. The scheduler is auto-selected by backend " +
+                     "type (hstore -> distributed, others -> local).");
+        }
+
         this.started = false;
         this.closed = false;
         this.mode = GraphMode.NONE;
         this.readMode = GraphReadMode.OLTP_ONLY;
-        this.schedulerType = config.get(CoreOptions.SCHEDULER_TYPE);
 
         // Init process-wide static configs before lock, so that validation
         // failures won't leave stale lock groups in LockManager.
@@ -323,6 +329,7 @@ public class StandardHugeGraph implements HugeGraph {
         return this.storeProvider.type();
     }
 
+    @Override
     public BackendStoreInfo backendStoreInfo() {
         // Just for trigger Tx.getOrNewTransaction, then load 3 stores
         // TODO: pass storeProvider.metaStore()
@@ -340,11 +347,10 @@ public class StandardHugeGraph implements HugeGraph {
         LOG.info("Init system info for graph '{}'", this.spaceGraphName());
         this.initSystemInfo();
 
-        LOG.info("Init server info [{}-{}] for graph '{}'...",
-                 nodeInfo.nodeId(), nodeInfo.nodeRole(), 
this.spaceGraphName());
-        this.serverInfoManager().initServerInfo(nodeInfo);
-
-        this.initRoleStateMachine(nodeInfo.nodeId());
+        if (nodeInfo != null && nodeInfo.nodeId() != null) {
+            this.serverInfoManager().initServerInfo(nodeInfo);
+            this.initRoleStateMachine(nodeInfo.nodeId());
+        }
 
         // TODO: check necessary?
         LOG.info("Check olap property-key tables for graph '{}'", 
this.spaceGraphName());
@@ -473,6 +479,7 @@ public class StandardHugeGraph implements HugeGraph {
         this.updateTime = updateTime;
     }
 
+    @Override
     public void waitStarted() {
         // Just for trigger Tx.getOrNewTransaction, then load 3 stores
         this.schemaTransaction();
@@ -489,9 +496,7 @@ public class StandardHugeGraph implements HugeGraph {
         try {
             this.storeProvider.init();
             /*
-             * NOTE: The main goal is to write the serverInfo to the central
-             * node, such as etcd, and also create the system schema in memory,
-             * which has no side effects
+             * NOTE: Create system schema in memory, which has no side effects.
              */
             this.initSystemInfo();
         } finally {
@@ -532,8 +537,7 @@ public class StandardHugeGraph implements HugeGraph {
         LockUtil.lock(this.spaceGraphName(), LockUtil.GRAPH_LOCK);
         try {
             this.storeProvider.truncate();
-            // TODO: remove this after serverinfo saved in etcd
-            this.serverStarted(this.serverInfoManager().globalNodeRoleInfo());
+            this.serverStarted(null);
         } finally {
             LockUtil.unlock(this.spaceGraphName(), LockUtil.GRAPH_LOCK);
         }
@@ -555,7 +559,6 @@ public class StandardHugeGraph implements HugeGraph {
     public void initSystemInfo() {
         try {
             this.taskScheduler().init();
-            this.serverInfoManager().init();
             this.authManager().init();
         } finally {
             this.closeTx();
@@ -1640,7 +1643,9 @@ public class StandardHugeGraph implements HugeGraph {
 
         @Override
         public String schedulerType() {
-            return StandardHugeGraph.this.schedulerType;
+            // Use distributed scheduler for hstore backend, otherwise use 
local
+            // After the merger of rocksdb and hstore, consider whether to 
change this logic
+            return StandardHugeGraph.this.isHstore() ? "distributed" : "local";
         }
     }
 
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/config/CoreOptions.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/config/CoreOptions.java
index 07109580a..9aa60e398 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/config/CoreOptions.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/config/CoreOptions.java
@@ -313,13 +313,7 @@ public class CoreOptions extends OptionHolder {
                     rangeInt(1, 500),
                     1
             );
-    public static final ConfigOption<String> SCHEDULER_TYPE =
-            new ConfigOption<>(
-                    "task.scheduler_type",
-                    "The type of scheduler used in distribution system.",
-                    allowValues("local", "distributed"),
-                    "local"
-            );
+
     public static final ConfigOption<Boolean> TASK_SYNC_DELETION =
             new ConfigOption<>(
                     "task.sync_deletion",
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/GlobalMasterInfo.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/GlobalMasterInfo.java
index c345c50e6..485674445 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/GlobalMasterInfo.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/GlobalMasterInfo.java
@@ -22,7 +22,7 @@ import org.apache.hugegraph.backend.id.IdGenerator;
 import org.apache.hugegraph.type.define.NodeRole;
 import org.apache.hugegraph.util.E;
 
-// TODO: rename to GlobalNodeRoleInfo
+// TODO: We need to completely delete the startup of master-worker
 public final class GlobalMasterInfo {
 
     private static final NodeInfo NO_MASTER = new NodeInfo(false, "");
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/StandardRoleListener.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/StandardRoleListener.java
index dbbea6d91..ce91ca2d5 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/StandardRoleListener.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/StandardRoleListener.java
@@ -36,7 +36,6 @@ public class StandardRoleListener implements RoleListener {
     public StandardRoleListener(TaskManager taskManager,
                                 GlobalMasterInfo roleInfo) {
         this.taskManager = taskManager;
-        this.taskManager.enableRoleElection();
         this.roleInfo = roleInfo;
         this.selfIsMaster = false;
     }
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/DistributedTaskScheduler.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/DistributedTaskScheduler.java
index 3929f8414..8b11db9b6 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/DistributedTaskScheduler.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/DistributedTaskScheduler.java
@@ -18,8 +18,10 @@
 package org.apache.hugegraph.task;
 
 import java.util.Iterator;
+import java.util.Set;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
@@ -48,6 +50,7 @@ import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.slf4j.Logger;
 
 public class DistributedTaskScheduler extends TaskAndResultScheduler {
+
     private static final Logger LOG = 
Log.logger(DistributedTaskScheduler.class);
     private final long schedulePeriod;
     private final ExecutorService taskDbExecutor;
@@ -64,6 +67,7 @@ public class DistributedTaskScheduler extends 
TaskAndResultScheduler {
     private final AtomicBoolean closed = new AtomicBoolean(true);
 
     private final ConcurrentHashMap<Id, HugeTask<?>> runningTasks = new 
ConcurrentHashMap<>();
+    private final Set<Id> deletingTasks = ConcurrentHashMap.newKeySet();
 
     public DistributedTaskScheduler(HugeGraphParams graph,
                                     ScheduledThreadPoolExecutor 
schedulerExecutor,
@@ -118,6 +122,11 @@ public class DistributedTaskScheduler extends 
TaskAndResultScheduler {
     public void cronSchedule() {
         // Perform periodic scheduling tasks
 
+        // Check closed flag first to exit early
+        if (this.closed.get()) {
+            return;
+        }
+
         if (!this.graph.started() || this.graph.closed()) {
             return;
         }
@@ -179,14 +188,17 @@ public class DistributedTaskScheduler extends 
TaskAndResultScheduler {
 
         while (!this.closed.get() && cancellings.hasNext()) {
             Id cancellingId = cancellings.next().id();
-            if (runningTasks.containsKey(cancellingId)) {
-                HugeTask<?> cancelling = runningTasks.get(cancellingId);
+            HugeTask<?> cancelling = runningTasks.get(cancellingId);
+            if (cancelling != null) {
                 initTaskParams(cancelling);
                 LOG.info("Try to cancel task({})@({}/{})",
                          cancelling.id(), this.graphSpace, this.graphName);
-                cancelling.cancel(true);
-
-                runningTasks.remove(cancellingId);
+                if (!cancelling.cancel(true)) {
+                    // Task already completed normally; force CANCELLED so
+                    // it doesn't stay stuck in CANCELLING forever.
+                    updateStatusWithLock(cancellingId, TaskStatus.CANCELLING,
+                                         TaskStatus.CANCELLED);
+                }
             } else {
                 // Local no execution task, but the current task has no nodes 
executing.
                 if (!isLockedTask(cancellingId.toString())) {
@@ -202,15 +214,10 @@ public class DistributedTaskScheduler extends 
TaskAndResultScheduler {
 
         while (!this.closed.get() && deletings.hasNext()) {
             Id deletingId = deletings.next().id();
-            if (runningTasks.containsKey(deletingId)) {
-                HugeTask<?> deleting = runningTasks.get(deletingId);
-                initTaskParams(deleting);
+            HugeTask<?> deleting = runningTasks.get(deletingId);
+            if (deleting != null) {
+                this.markTaskDeleting(deleting);
                 deleting.cancel(true);
-
-                // Delete storage information
-                deleteFromDB(deletingId);
-
-                runningTasks.remove(deletingId);
             } else {
                 // Local has no task execution, but the current task has no 
nodes executing anymore.
                 if (!isLockedTask(deletingId.toString())) {
@@ -253,6 +260,10 @@ public class DistributedTaskScheduler extends 
TaskAndResultScheduler {
             return this.ephemeralTaskExecutor.submit(task);
         }
 
+        // Validate task state before saving to ensure correct exception type
+        E.checkState(task.type() != null, "Task type can't be null");
+        E.checkState(task.name() != null, "Task name can't be null");
+
         // Process schema task
         // Handle gremlin task
         // Handle OLAP calculation tasks
@@ -284,14 +295,63 @@ public class DistributedTaskScheduler extends 
TaskAndResultScheduler {
         }
     }
 
+    /**
+     * Note: This method will update the status of the input task.
+     *
+     * @param task
+     * @param <V>
+     */
     @Override
     public <V> void cancel(HugeTask<V> task) {
-        // Update status to CANCELLING
-        if (!task.completed()) {
-            // Task not completed, can only execute status not CANCELLING
-            this.updateStatus(task.id(), null, TaskStatus.CANCELLING);
+        E.checkArgumentNotNull(task, "Task can't be null");
+
+        if (task.completed() || task.cancelling()) {
+            return;
+        }
+
+        LOG.info("Cancel task '{}' in status {}", task.id(), task.status());
+
+        // Check if task is running locally, cancel it directly if so
+        HugeTask<?> runningTask = this.runningTasks.get(task.id());
+        if (runningTask != null) {
+            boolean cancelled = runningTask.cancel(true);
+            if (cancelled) {
+                task.overwriteStatus(TaskStatus.CANCELLED);
+                this.save(runningTask);
+            }
+            LOG.info("Cancel local running task '{}' result: {}", task.id(), 
cancelled);
+            return;
+        }
+
+        // Task not running locally, update status to CANCELLING
+        // for cronSchedule() or other nodes to handle
+        TaskStatus currentStatus = task.status();
+        if (this.updateStatus(task.id(), currentStatus, 
TaskStatus.CANCELLING)) {
+            task.overwriteStatus(TaskStatus.CANCELLING);
         } else {
-            LOG.info("cancel task({}) error, task has completed", task.id());
+            // Status race: re-read from DB and retry with fresh status
+            HugeTask<Object> reloaded;
+            try {
+                reloaded = this.taskWithoutResult(task.id());
+            } catch (NotFoundException e) {
+                LOG.info("Task '{}' already deleted, skip cancel", task.id());
+                return;
+            }
+            TaskStatus stored = reloaded.status();
+            if (stored != TaskStatus.CANCELLING &&
+                !TaskStatus.COMPLETED_STATUSES.contains(stored)) {
+                if (this.updateStatus(task.id(), stored, 
TaskStatus.CANCELLING)) {
+                    task.overwriteStatus(TaskStatus.CANCELLING);
+                    LOG.info("Retry cancel task '{}' succeeded (stored was 
{})",
+                             task.id(), stored);
+                } else {
+                    LOG.warn("Failed to cancel task '{}', re-read status {} 
changed again",
+                             task.id(), stored);
+                }
+            } else {
+                LOG.info("Task '{}' already {}/terminal, skip cancel",
+                         task.id(), stored);
+            }
         }
     }
 
@@ -302,38 +362,166 @@ public class DistributedTaskScheduler extends 
TaskAndResultScheduler {
 
     protected <V> HugeTask<V> deleteFromDB(Id id) {
         // Delete Task from DB, without checking task status
-        return this.call(() -> {
-            Iterator<Vertex> vertices = this.tx().queryTaskInfos(id);
-            HugeVertex vertex = (HugeVertex) QueryResults.one(vertices);
-            if (vertex == null) {
+        try {
+            return this.call(() -> {
+                Iterator<Vertex> vertices = this.tx().queryTaskInfos(id);
+                HugeVertex vertex = (HugeVertex) QueryResults.one(vertices);
+                if (vertex == null) {
+                    this.deleteTaskResultFromTx(id);
+                    return null;
+                }
+                HugeTask<V> result = HugeTask.fromVertex(vertex, false);
+                // Keep the task vertex as a retryable tombstone until its 
result
+                // vertex is removed; cronSchedule() can rediscover DELETING 
tasks.
                 this.deleteTaskResultFromTx(id);
+                this.tx().removeTaskVertex(vertex);
+                return result;
+            });
+        } finally {
+            if (!this.runningTasks.containsKey(id)) {
+                this.deletingTasks.remove(id);
+            }
+        }
+    }
+
+    @Override
+    public <V> void save(HugeTask<V> task) {
+        E.checkArgumentNotNull(task, "Task can't be null");
+        if (this.deletingTasks.contains(task.id())) {
+            LOG.info("Skip saving task({})@({}/{}) because it is deleting",
+                     task.id(), this.graphSpace, this.graphName);
+            return;
+        }
+
+        String rawResult = task.result();
+        Boolean saved = this.call(() -> {
+            if (task.status() != TaskStatus.DELETING &&
+                this.storedTaskDeleting(task.id())) {
+                LOG.info("Skip saving task({})@({}/{}) because stored status " 
+
+                         "is DELETING", task.id(), this.graphSpace,
+                         this.graphName);
+                return false;
+            }
+            HugeVertex vertex = this.tx().constructTaskVertex(task);
+            this.tx().deleteIndex(vertex);
+            this.tx().addVertex(vertex);
+            return true;
+        });
+
+        if (!saved || rawResult == null) {
+            return;
+        }
+
+        this.call(() -> {
+            if (this.deletingTasks.contains(task.id()) ||
+                !this.storedTaskAllowsResultSave(task.id())) {
+                LOG.info("Skip saving task({}) result@({}/{}) because it is " +
+                         "deleting or missing", task.id(), this.graphSpace,
+                         this.graphName);
                 return null;
             }
-            HugeTask<V> result = HugeTask.fromVertex(vertex, false);
-            // Keep the task vertex as a retryable tombstone until its result
-            // vertex is removed; cronSchedule() can rediscover DELETING tasks.
-            this.deleteTaskResultFromTx(id);
-            this.tx().removeTaskVertex(vertex);
-            return result;
+            HugeTaskResult result =
+                    new HugeTaskResult(HugeTaskResult.genId(task.id()));
+            result.result(rawResult);
+
+            HugeVertex vertex = this.tx().constructTaskResultVertex(result);
+            return this.tx().addVertex(vertex);
+        });
+    }
+
+    private void markTaskDeleting(HugeTask<?> task) {
+        this.deletingTasks.add(task.id());
+        initTaskParams(task);
+        HugeTask<?> deleting;
+        synchronized (task) {
+            task.overwriteStatus(TaskStatus.DELETING);
+            deleting = task.copyWithoutResult();
+        }
+        this.saveTaskWithoutResult(deleting);
+    }
+
+    private boolean storedTaskDeleting(Id id) {
+        Iterator<Vertex> vertices = this.tx().queryTaskInfos(id);
+        Vertex vertex = QueryResults.one(vertices);
+        if (vertex == null) {
+            return false;
+        }
+        HugeTask<?> task = HugeTask.fromVertex(vertex, false);
+        return task.status() == TaskStatus.DELETING;
+    }
+
+    private boolean storedTaskAllowsResultSave(Id id) {
+        Iterator<Vertex> vertices = this.tx().queryTaskInfos(id);
+        Vertex vertex = QueryResults.one(vertices);
+        if (vertex == null) {
+            return false;
+        }
+        HugeTask<?> task = HugeTask.fromVertex(vertex, false);
+        return task.status() != TaskStatus.DELETING;
+    }
+
+    private void saveTaskWithoutResult(HugeTask<?> task) {
+        this.call(() -> {
+            HugeVertex vertex = this.tx().constructTaskVertex(task);
+            this.tx().deleteIndex(vertex);
+            return this.tx().addVertex(vertex);
         });
     }
 
     @Override
     public <V> HugeTask<V> delete(Id id, boolean force) {
-        if (!force) {
-            // Change status to DELETING, perform the deletion operation 
through automatic
-            // scheduling.
-            this.updateStatus(id, null, TaskStatus.DELETING);
-            return null;
-        } else {
-            HugeTask<?> task = this.taskWithoutResult(id);
-            if (task != null && task.status() != TaskStatus.DELETING) {
-                initTaskParams(task);
-                task.overwriteStatus(TaskStatus.DELETING);
-                this.save(task);
+        HugeTask<?> task = this.taskWithoutResult(id);
+        HugeTask<?> running = this.runningTasks.get(id);
+
+        if (running != null) {
+            this.markTaskDeleting(running);
+            running.cancel(true);
+            @SuppressWarnings("unchecked")
+            HugeTask<V> result = (HugeTask<V>) running;
+            return result;
+        }
+
+        if (!force && !task.completed()) {
+            // Can't safely mark a remotely running task without owning its
+            // lock; the owner may otherwise overwrite DELETING on final save.
+            LockResult lockResult = tryLockTask(id.asString());
+            checkDeleteLock(id, lockResult);
+            try {
+                this.markTaskDeleting(task);
+            } finally {
+                unlockTask(id.asString(), lockResult);
+            }
+            @SuppressWarnings("unchecked")
+            HugeTask<V> result = (HugeTask<V>) task;
+            return result;
+        }
+
+        if (!task.completed()) {
+            LockResult lockResult = tryLockTask(id.asString());
+            checkDeleteLock(id, lockResult);
+            try {
+                if (task.status() != TaskStatus.DELETING) {
+                    this.markTaskDeleting(task);
+                }
+                return this.deleteFromDB(id);
+            } finally {
+                unlockTask(id.asString(), lockResult);
             }
-            return this.deleteFromDB(id);
         }
+
+        // Write DELETING status before attempting physical delete so that a
+        // failed result deletion is recoverable via cronSchedule().
+        if (task.status() != TaskStatus.DELETING) {
+            this.markTaskDeleting(task);
+        }
+
+        return this.deleteFromDB(id);
+    }
+
+    private static void checkDeleteLock(Id id, LockResult lockResult) {
+        E.checkState(lockResult.lockSuccess(),
+                     "Can't delete task '%s' because it is locked by another " 
+
+                     "server, please retry later", id);
     }
 
     @Override
@@ -345,6 +533,26 @@ public class DistributedTaskScheduler extends 
TaskAndResultScheduler {
         // set closed
         this.closed.set(true);
 
+        // cancel cron thread
+        if (!cronFuture.isDone() && !cronFuture.isCancelled()) {
+            cronFuture.cancel(false);
+        }
+
+        // Wait behind the scheduler thread to ensure any running cron task is 
completed
+        try {
+            Future<?> barrier = this.schedulerExecutor.submit(() -> {
+                // pass
+            });
+            barrier.get(schedulePeriod + 5, TimeUnit.SECONDS);
+        } catch (TimeoutException e) {
+            LOG.warn("Cron task did not complete in time when closing 
scheduler");
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            LOG.warn("Interrupted while waiting for cron task to complete", e);
+        } catch (ExecutionException e) {
+            LOG.warn("Exception while waiting for cron task to complete", e);
+        }
+
         // cancel all running tasks
         for (HugeTask<?> task : this.runningTasks.values()) {
             LOG.info("cancel task({}) @({}/{}) when closing scheduler",
@@ -356,11 +564,7 @@ public class DistributedTaskScheduler extends 
TaskAndResultScheduler {
             this.waitUntilAllTasksCompleted(10);
         } catch (TimeoutException e) {
             LOG.warn("Tasks not completed when close distributed task 
scheduler", e);
-        }
-
-        // cancel cron thread
-        if (!cronFuture.isDone() && !cronFuture.isCancelled()) {
-            cronFuture.cancel(false);
+            return false;
         }
 
         if (!this.taskDbExecutor.isShutdown()) {
@@ -373,7 +577,9 @@ public class DistributedTaskScheduler extends 
TaskAndResultScheduler {
                 this.graph.closeTx();
             });
         }
-        return true;
+
+        // TODO: serverInfoManager section should be removed in the future.
+        return this.serverManager().close();
     }
 
     @Override
@@ -447,9 +653,7 @@ public class DistributedTaskScheduler extends 
TaskAndResultScheduler {
 
     @Override
     public void checkRequirement(String op) {
-        if (!this.serverManager().selfIsMaster()) {
-            throw new HugeException("Can't %s task on non-master server", op);
-        }
+        // Distributed scheduler uses task locks to coordinate workers.
     }
 
     @Override
@@ -654,6 +858,7 @@ public class DistributedTaskScheduler extends 
TaskAndResultScheduler {
                     LOG.warn("exception when execute task", t);
                 } finally {
                     runningTasks.remove(task.id());
+                    deletingTasks.remove(task.id());
                     unlockTask(task.id().asString(), lockResult);
 
                     LOG.info("task({}) finished.", task.id().toString());
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/HugeServerInfo.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/HugeServerInfo.java
index 71feb3f68..f0485f665 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/HugeServerInfo.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/HugeServerInfo.java
@@ -209,14 +209,6 @@ public class HugeServerInfo {
         return serverInfo;
     }
 
-    public <V> boolean suitableFor(HugeTask<V> task, long now) {
-        if (task.computer() != this.role.computer()) {
-            return false;
-        }
-        return this.updateTime.getTime() + EXPIRED_INTERVAL >= now &&
-               this.load() + task.load() <= this.maxLoad;
-    }
-
     public static Schema schema(HugeGraphParams graph) {
         return new Schema(graph);
     }
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/HugeTask.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/HugeTask.java
index d5d703928..f63d4c076 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/HugeTask.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/HugeTask.java
@@ -319,12 +319,20 @@ public class HugeTask<V> extends FutureTask<V> {
     public boolean cancel(boolean mayInterruptIfRunning) {
         // NOTE: Gremlin sleep() can't be interrupted by default
         // 
https://mrhaki.blogspot.com/2016/10/groovy-goodness-interrupted-sleeping.html
+        TaskStatus prevStatus = this.status;
         boolean cancelled = super.cancel(mayInterruptIfRunning);
         if (!cancelled) {
             return cancelled;
         }
 
         try {
+            // If the task is being deleted, don't transition to CANCELLED or
+            // fire cancelled() callback — let cronSchedule() handle the actual
+            // DB deletion. Prevents an async save() from resurrecting the task
+            // after deleteFromDB() has already removed it.
+            if (prevStatus == TaskStatus.DELETING) {
+                return cancelled;
+            }
             if (this.status(TaskStatus.CANCELLED)) {
                 // Callback for saving status to store
                 this.callable.cancelled();
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/ServerInfoManager.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/ServerInfoManager.java
index 1560ec0b8..dac78f2fc 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/ServerInfoManager.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/ServerInfoManager.java
@@ -17,55 +17,26 @@
 
 package org.apache.hugegraph.task;
 
-import static org.apache.hugegraph.backend.query.Query.NO_LIMIT;
-
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.Map;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutorService;
 
 import org.apache.hugegraph.HugeException;
-import org.apache.hugegraph.HugeGraph;
 import org.apache.hugegraph.HugeGraphParams;
 import org.apache.hugegraph.backend.id.Id;
 import org.apache.hugegraph.backend.id.IdGenerator;
-import org.apache.hugegraph.backend.page.PageInfo;
-import org.apache.hugegraph.backend.query.Condition;
-import org.apache.hugegraph.backend.query.ConditionQuery;
-import org.apache.hugegraph.backend.query.QueryResults;
 import org.apache.hugegraph.backend.tx.GraphTransaction;
 import org.apache.hugegraph.exception.ConnectionException;
-import org.apache.hugegraph.iterator.ListIterator;
-import org.apache.hugegraph.iterator.MapperIterator;
 import org.apache.hugegraph.masterelection.GlobalMasterInfo;
-import org.apache.hugegraph.schema.PropertyKey;
-import org.apache.hugegraph.schema.VertexLabel;
-import org.apache.hugegraph.structure.HugeVertex;
-import org.apache.hugegraph.type.HugeType;
-import org.apache.hugegraph.type.define.HugeKeys;
 import org.apache.hugegraph.type.define.NodeRole;
-import org.apache.hugegraph.util.DateUtil;
 import org.apache.hugegraph.util.E;
-import org.apache.hugegraph.util.Log;
-import org.apache.tinkerpop.gremlin.structure.Vertex;
-import org.slf4j.Logger;
-
-import com.google.common.collect.ImmutableMap;
 
 public class ServerInfoManager {
 
-    private static final Logger LOG = Log.logger(ServerInfoManager.class);
-
-    public static final long MAX_SERVERS = 100000L;
-    public static final long PAGE_SIZE = 10L;
-
     private final HugeGraphParams graph;
     private final ExecutorService dbExecutor;
 
     private volatile GlobalMasterInfo globalNodeInfo;
 
-    private volatile boolean onlySingleNode;
     private volatile boolean closed;
 
     public ServerInfoManager(HugeGraphParams graph, ExecutorService 
dbExecutor) {
@@ -77,28 +48,17 @@ public class ServerInfoManager {
 
         this.globalNodeInfo = null;
 
-        this.onlySingleNode = false;
         this.closed = false;
     }
 
     public void init() {
-        HugeServerInfo.schema(this.graph).initSchemaIfNeeded();
+        // ServerInfo is soft-disabled; keep this method for compatibility.
     }
 
     public synchronized boolean close() {
+        // ServerInfo persistence is soft-deprecated; init() and heartbeat()
+        // are no-ops, so there's nothing to clean up in close().
         this.closed = true;
-        if (!this.dbExecutor.isShutdown()) {
-            this.removeSelfServerInfo();
-            this.call(() -> {
-                try {
-                    this.tx().close();
-                } catch (ConnectionException ignored) {
-                    // ConnectionException means no connection established
-                }
-                this.graph.closeTx();
-                return null;
-            });
-        }
         return true;
     }
 
@@ -106,53 +66,14 @@ public class ServerInfoManager {
         E.checkArgument(nodeInfo != null, "The global node info can't be 
null");
 
         this.globalNodeInfo = nodeInfo;
-
-        Id serverId = this.selfNodeId();
-        HugeServerInfo existed = this.serverInfo(serverId);
-        if (existed != null && existed.alive()) {
-            final long now = DateUtil.now().getTime();
-            if (existed.expireTime() > now + 30 * 1000) {
-                LOG.info("The node time maybe skew very much: {}", existed);
-                throw new HugeException("The server with name '%s' maybe skew 
very much", serverId);
-            }
-            try {
-                Thread.sleep(existed.expireTime() - now + 1);
-            } catch (InterruptedException e) {
-               throw new HugeException("Interrupted when waiting for server 
info expired", e);
-            }
-        }
-        E.checkArgument(existed == null || !existed.alive(),
-                        "The server with name '%s' already in cluster", 
serverId);
-
-        if (nodeInfo.nodeRole().master()) {
-            String page = this.supportsPaging() ? PageInfo.PAGE_NONE : null;
-            do {
-                Iterator<HugeServerInfo> servers = this.serverInfos(PAGE_SIZE, 
page);
-                while (servers.hasNext()) {
-                    existed = servers.next();
-                    E.checkArgument(!existed.role().master() || 
!existed.alive(),
-                                    "Already existed master '%s' in current 
cluster",
-                                    existed.id());
-                }
-                if (page != null) {
-                    page = PageInfo.pageInfo(servers);
-                }
-            } while (page != null);
-        }
-
-        // TODO: save ServerInfo to AuthServer
-        this.saveServerInfo(this.selfNodeId(), this.selfNodeRole());
     }
 
     public synchronized void changeServerRole(NodeRole nodeRole) {
-        if (this.closed) {
+        if (this.closed || this.globalNodeInfo == null) {
             return;
         }
 
         this.globalNodeInfo.changeNodeRole(nodeRole);
-
-        // TODO: save ServerInfo to AuthServer
-        this.saveServerInfo(this.selfNodeId(), this.selfNodeRole());
     }
 
     public GlobalMasterInfo globalNodeRoleInfo() {
@@ -163,9 +84,13 @@ public class ServerInfoManager {
         if (this.globalNodeInfo == null) {
             return null;
         }
+        Id nodeId = this.globalNodeInfo.nodeId();
+        if (nodeId == null) {
+            return null;
+        }
         // Scope server id to graph to avoid cross-graph collision
         return IdGenerator.of(this.graph.spaceGraphName() + "/" +
-                             this.globalNodeInfo.nodeId().asString());
+                             nodeId.asString());
     }
 
     public NodeRole selfNodeRole() {
@@ -179,98 +104,8 @@ public class ServerInfoManager {
         return this.selfNodeRole() != null && this.selfNodeRole().master();
     }
 
-    public boolean onlySingleNode() {
-        // Only exists one node in the whole master
-        return this.onlySingleNode;
-    }
-
     public synchronized void heartbeat() {
-        assert this.graphIsReady();
-
-        HugeServerInfo serverInfo = this.selfServerInfo();
-        if (serverInfo != null) {
-            // Update heartbeat time for this server
-            serverInfo.updateTime(DateUtil.now());
-            this.save(serverInfo);
-            return;
-        }
-
-        /* ServerInfo is missing */
-        if (this.selfNodeId() == null) {
-            // Ignore if ServerInfo is not initialized
-            LOG.info("ServerInfo is missing: {}, may not be initialized yet", 
this.selfNodeId());
-            return;
-        }
-        if (this.selfIsMaster()) {
-            // On the master node, just wait for ServerInfo re-init
-            LOG.warn("ServerInfo is missing: {}, may be cleared before", 
this.selfNodeId());
-            return;
-        }
-        /*
-         * Missing server info on non-master node, may be caused by graph
-         * truncated on master node then synced by raft.
-         * TODO: we just patch it here currently, to be improved.
-         */
-        serverInfo = this.saveServerInfo(this.selfNodeId(), 
this.selfNodeRole());
-        assert serverInfo != null;
-    }
-
-    public synchronized void decreaseLoad(int load) {
-        assert load > 0 : load;
-        HugeServerInfo serverInfo = this.selfServerInfo();
-        serverInfo.increaseLoad(-load);
-        this.save(serverInfo);
-    }
-
-    public int calcMaxLoad() {
-        // TODO: calc max load based on CPU and Memory resources
-        return 10000;
-    }
-
-    protected boolean graphIsReady() {
-        return !this.closed && this.graph.started() && 
this.graph.initialized();
-    }
-
-    protected synchronized HugeServerInfo 
pickWorkerNode(Collection<HugeServerInfo> servers,
-                                                         HugeTask<?> task) {
-        HugeServerInfo master = null;
-        HugeServerInfo serverWithMinLoad = null;
-        int minLoad = Integer.MAX_VALUE;
-        boolean hasWorkerNode = false;
-        long now = DateUtil.now().getTime();
-
-        // Iterate servers to find suitable one
-        for (HugeServerInfo server : servers) {
-            if (!server.alive()) {
-                continue;
-            }
-            if (server.role().master()) {
-                master = server;
-                continue;
-            }
-            hasWorkerNode = true;
-            if (!server.suitableFor(task, now)) {
-                continue;
-            }
-            if (server.load() < minLoad) {
-                minLoad = server.load();
-                serverWithMinLoad = server;
-            }
-        }
-
-        boolean singleNode = !hasWorkerNode;
-        if (singleNode != this.onlySingleNode) {
-            LOG.info("Switch only_single_node to {}", singleNode);
-            this.onlySingleNode = singleNode;
-        }
-
-        // Only schedule to master if there are no workers and master are 
suitable
-        if (!hasWorkerNode) {
-            if (master != null && master.suitableFor(task, now)) {
-                serverWithMinLoad = master;
-            }
-        }
-        return serverWithMinLoad;
+        // ServerInfo heartbeat is deprecated for local scheduling.
     }
 
     private GraphTransaction tx() {
@@ -278,57 +113,6 @@ public class ServerInfoManager {
         return this.graph.systemTransaction();
     }
 
-    private HugeServerInfo saveServerInfo(Id serverId, NodeRole serverRole) {
-        HugeServerInfo serverInfo = new HugeServerInfo(serverId, serverRole);
-        serverInfo.maxLoad(this.calcMaxLoad());
-        this.save(serverInfo);
-
-        LOG.info("Init server info: {}", serverInfo);
-        return serverInfo;
-    }
-
-    private Id save(HugeServerInfo serverInfo) {
-        return this.call(() -> {
-            // Construct vertex from server info
-            HugeServerInfo.Schema schema = HugeServerInfo.schema(this.graph);
-            if (!schema.existVertexLabel(HugeServerInfo.P.SERVER)) {
-                throw new HugeException("Schema is missing for %s '%s'",
-                                        HugeServerInfo.P.SERVER, serverInfo);
-            }
-            HugeVertex vertex = this.tx().constructVertex(false, 
serverInfo.asArray());
-            // Add or update server info in backend store
-            vertex = this.tx().addVertex(vertex);
-            return vertex.id();
-        });
-    }
-
-    private int save(Collection<HugeServerInfo> serverInfos) {
-        return this.call(() -> {
-            if (serverInfos.isEmpty()) {
-                return 0;
-            }
-            HugeServerInfo.Schema schema = HugeServerInfo.schema(this.graph);
-            if (!schema.existVertexLabel(HugeServerInfo.P.SERVER)) {
-                throw new HugeException("Schema is missing for %s", 
HugeServerInfo.P.SERVER);
-            }
-            // Save server info in batch
-            GraphTransaction tx = this.tx();
-            int updated = 0;
-            for (HugeServerInfo server : serverInfos) {
-                if (!server.updated()) {
-                    continue;
-                }
-                HugeVertex vertex = tx.constructVertex(false, 
server.asArray());
-                tx.addVertex(vertex);
-                updated++;
-            }
-            // NOTE: actually it is auto-commit, to be improved
-            tx.commitOrRollback();
-
-            return updated;
-        });
-    }
-
     private <V> V call(Callable<V> callable) {
         assert !Thread.currentThread().getName().startsWith(
                 "server-info-db-worker") : "can't call by itself";
@@ -342,110 +126,4 @@ public class ServerInfoManager {
                                     e, e.toString());
         }
     }
-
-    private HugeServerInfo selfServerInfo() {
-        HugeServerInfo selfServerInfo = this.serverInfo(this.selfNodeId());
-        if (selfServerInfo == null && this.selfNodeId() != null) {
-            LOG.warn("ServerInfo is missing: {}", this.selfNodeId());
-        }
-        return selfServerInfo;
-    }
-
-    private HugeServerInfo serverInfo(Id serverId) {
-        return this.call(() -> {
-            Iterator<Vertex> vertices = this.tx().queryServerInfos(serverId);
-            Vertex vertex = QueryResults.one(vertices);
-            if (vertex == null) {
-                return null;
-            }
-            return HugeServerInfo.fromVertex(vertex);
-        });
-    }
-
-    private HugeServerInfo removeSelfServerInfo() {
-        /*
-         * Check this.selfServerId != null to avoid graph.initialized() call.
-         * NOTE: graph.initialized() may throw exception if we can't connect to
-         * backend store, initServerInfo() is not called in this case, so
-         * this.selfServerId is null at this time.
-         */
-        if (this.selfNodeId() != null && this.graph.initialized()) {
-            return this.removeServerInfo(this.selfNodeId());
-        }
-        return null;
-    }
-
-    private HugeServerInfo removeServerInfo(Id serverId) {
-        if (serverId == null) {
-            return null;
-        }
-        LOG.info("Remove server info: {}", serverId);
-        return this.call(() -> {
-            Iterator<Vertex> vertices = this.tx().queryServerInfos(serverId);
-            Vertex vertex = QueryResults.one(vertices);
-            if (vertex == null) {
-                return null;
-            }
-            this.tx().removeVertex((HugeVertex) vertex);
-            return HugeServerInfo.fromVertex(vertex);
-        });
-    }
-
-    protected void updateServerInfos(Collection<HugeServerInfo> serverInfos) {
-        this.save(serverInfos);
-    }
-
-    protected Collection<HugeServerInfo> allServerInfos() {
-        Iterator<HugeServerInfo> infos = this.serverInfos(NO_LIMIT, null);
-        try (ListIterator<HugeServerInfo> iter = new ListIterator<>(
-                MAX_SERVERS, infos)) {
-            return iter.list();
-        } catch (Exception e) {
-            throw new HugeException("Failed to close server info iterator", e);
-        }
-    }
-
-    protected Iterator<HugeServerInfo> serverInfos(String page) {
-        return this.serverInfos(ImmutableMap.of(), PAGE_SIZE, page);
-    }
-
-    protected Iterator<HugeServerInfo> serverInfos(long limit, String page) {
-        return this.serverInfos(ImmutableMap.of(), limit, page);
-    }
-
-    private Iterator<HugeServerInfo> serverInfos(Map<String, Object> 
conditions,
-                                                 long limit, String page) {
-        return this.call(() -> {
-            ConditionQuery query;
-            if 
(this.graph.backendStoreFeatures().supportsTaskAndServerVertex()) {
-                query = new ConditionQuery(HugeType.SERVER);
-            } else {
-                query = new ConditionQuery(HugeType.VERTEX);
-            }
-            if (page != null) {
-                query.page(page);
-            }
-
-            HugeGraph graph = this.graph.graph();
-            VertexLabel vl = graph.vertexLabel(HugeServerInfo.P.SERVER);
-            query.eq(HugeKeys.LABEL, vl.id());
-            for (Map.Entry<String, Object> entry : conditions.entrySet()) {
-                PropertyKey pk = graph.propertyKey(entry.getKey());
-                query.query(Condition.eq(pk.id(), entry.getValue()));
-            }
-            query.showHidden(true);
-            if (limit != NO_LIMIT) {
-                query.limit(limit);
-            }
-            Iterator<Vertex> vertices = this.tx().queryServerInfos(query);
-            Iterator<HugeServerInfo> servers =
-                    new MapperIterator<>(vertices, HugeServerInfo::fromVertex);
-            // Convert iterator to list to avoid across thread tx accessed
-            return QueryResults.toList(servers);
-        });
-    }
-
-    private boolean supportsPaging() {
-        return this.graph.graph().backendStoreFeatures().supportsQueryByPage();
-    }
 }
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/StandardTaskScheduler.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/StandardTaskScheduler.java
index 1438249a4..269094bc7 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/StandardTaskScheduler.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/StandardTaskScheduler.java
@@ -18,7 +18,6 @@
 package org.apache.hugegraph.task;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -125,11 +124,9 @@ public class StandardTaskScheduler implements 
TaskScheduler {
         // NOTE: only the owner thread can access task tx
         if (this.taskTx == null) {
             /*
-             * NOTE: don't synchronized(this) due to scheduler thread hold
-             * this lock through scheduleTasks(), then query tasks and wait
-             * for db-worker thread after call(), the tx may not be initialized
-             * but can't catch this lock, then cause deadlock.
-             * We just use this.serverManager as a monitor here
+             * NOTE: don't synchronized(this) to avoid potential deadlock
+             * when multiple threads are accessing task transaction.
+             * We use this.serverManager as a monitor here for thread safety.
              */
             synchronized (this.serverManager) {
                 if (this.taskTx == null) {
@@ -146,9 +143,10 @@ public class StandardTaskScheduler implements 
TaskScheduler {
 
     @Override
     public <V> void restoreTasks() {
-        Id selfServer = this.serverManager().selfNodeId();
         List<HugeTask<V>> taskList = new ArrayList<>();
-        // Restore 'RESTORING', 'RUNNING' and 'QUEUED' tasks in order.
+        // Single-node mode: restore pending tasks without server filtering.
+        // Don't restore legacy SCHEDULING/SCHEDULED tasks globally; they were
+        // owned by the removed master-worker scheduler.
         for (TaskStatus status : TaskStatus.PENDING_STATUSES) {
             String page = this.supportsPaging() ? PageInfo.PAGE_NONE : null;
             do {
@@ -156,9 +154,7 @@ public class StandardTaskScheduler implements TaskScheduler 
{
                 for (iter = this.findTask(status, PAGE_SIZE, page, false);
                      iter.hasNext(); ) {
                     HugeTask<V> task = iter.next();
-                    if (selfServer.equals(task.server())) {
-                        taskList.add(task);
-                    }
+                    taskList.add(task);
                 }
                 if (page != null) {
                     page = PageInfo.pageInfo(iter);
@@ -211,33 +207,15 @@ public class StandardTaskScheduler implements 
TaskScheduler {
             return this.submitTask(task);
         }
 
-        // Check this is on master for normal task schedule
-        this.checkOnMasterNode("schedule");
-        if (this.serverManager().onlySingleNode() && !task.computer()) {
-            /*
-             * Speed up for single node, submit the task immediately,
-             * this code can be removed without affecting code logic
-             */
-            task.status(TaskStatus.QUEUED);
-            task.server(this.serverManager().selfNodeId());
-            this.save(task);
-            return this.submitTask(task);
-        } else {
-            /*
-             * Just set the SCHEDULING status and save the task,
-             * it will be scheduled by periodic scheduler worker
-             */
-            task.status(TaskStatus.SCHEDULING);
-            this.save(task);
-
-            // Notify master server to schedule and execute immediately
-            TaskManager.instance().notifyNewTask(task);
-
-            return task;
-        }
+        task.status(TaskStatus.QUEUED);
+        return this.submitTask(task, true);
     }
 
     private <V> Future<?> submitTask(HugeTask<V> task) {
+        return this.submitTask(task, false);
+    }
+
+    private <V> Future<?> submitTask(HugeTask<V> task, boolean 
saveAfterQueued) {
         int size = this.tasks.size() + 1;
         E.checkArgument(size <= MAX_PENDING_TASKS,
                         "Pending tasks size %s has exceeded the max limit %s",
@@ -245,6 +223,14 @@ public class StandardTaskScheduler implements 
TaskScheduler {
         this.initTaskCallable(task);
         assert !this.tasks.containsKey(task.id()) : task;
         this.tasks.put(task.id(), task);
+        if (saveAfterQueued) {
+            try {
+                this.save(task);
+            } catch (RuntimeException e) {
+                this.tasks.remove(task.id());
+                throw e;
+            }
+        }
         return this.taskExecutor.submit(task);
     }
 
@@ -273,7 +259,6 @@ public class StandardTaskScheduler implements TaskScheduler 
{
     @Override
     public synchronized <V> void cancel(HugeTask<V> task) {
         E.checkArgumentNotNull(task, "Task can't be null");
-        this.checkOnMasterNode("cancel");
 
         if (task.completed() || task.cancelling()) {
             return;
@@ -281,31 +266,18 @@ public class StandardTaskScheduler implements 
TaskScheduler {
 
         LOG.info("Cancel task '{}' in status {}", task.id(), task.status());
 
-        if (task.server() == null) {
-            // The task not scheduled to workers, set canceled immediately
-            assert task.status().code() < TaskStatus.QUEUED.code();
-            if (task.status(TaskStatus.CANCELLED)) {
-                this.save(task);
-                return;
+        HugeTask<?> memTask = this.tasks.get(task.id());
+        if (memTask != null) {
+            boolean cancelled = memTask.cancel(true);
+            if (cancelled) {
+                task.overwriteStatus(TaskStatus.CANCELLED);
             }
-        } else if (task.status(TaskStatus.CANCELLING)) {
-            // The task scheduled to workers, let the worker node to cancel
+            LOG.info("Task '{}' cancel result: {}", task.id(), cancelled);
+            return;
+        }
+
+        if (task.status(TaskStatus.CANCELLED)) {
             this.save(task);
-            assert task.server() != null : task;
-            assert this.serverManager().selfIsMaster();
-            if (!task.server().equals(this.serverManager().selfNodeId())) {
-                /*
-                 * Remove the task from memory if it's running on worker node,
-                 * but keep the task in memory if it's running on master node.
-                 * Cancel-scheduling will read the task from backend store, if
-                 * removed this instance from memory, there will be two task
-                 * instances with the same id, and can't cancel the real task 
that
-                 * is running but removed from memory.
-                 */
-                this.remove(task);
-            }
-            // Notify master server to schedule and execute immediately
-            TaskManager.instance().notifyNewTask(task);
             return;
         }
 
@@ -317,132 +289,11 @@ public class StandardTaskScheduler implements 
TaskScheduler {
     public ServerInfoManager serverManager() {
         return this.serverManager;
     }
-
-    protected synchronized void scheduleTasksOnMaster() {
-        // Master server schedule all scheduling tasks to suitable worker nodes
-        Collection<HugeServerInfo> serverInfos = 
this.serverManager().allServerInfos();
-        String page = this.supportsPaging() ? PageInfo.PAGE_NONE : null;
-        do {
-            Iterator<HugeTask<Object>> tasks = 
this.tasks(TaskStatus.SCHEDULING, PAGE_SIZE, page,
-                                                          false);
-            while (tasks.hasNext()) {
-                HugeTask<?> task = tasks.next();
-                if (task.server() != null) {
-                    // Skip if already scheduled
-                    continue;
-                }
-
-                if (!this.serverManager.selfIsMaster()) {
-                    return;
-                }
-
-                HugeServerInfo server = 
this.serverManager().pickWorkerNode(serverInfos, task);
-                if (server == null) {
-                    LOG.info("The master can't find suitable servers to " +
-                             "execute task '{}', wait for next schedule", 
task.id());
-                    continue;
-                }
-
-                // Found suitable server, update task status
-                assert server.id() != null;
-                task.server(server.id());
-                task.status(TaskStatus.SCHEDULED);
-                this.save(task);
-
-                // Update server load in memory, it will be saved at the ending
-                server.increaseLoad(task.load());
-
-                LOG.info("Scheduled task '{}' to server '{}'", task.id(), 
server.id());
-            }
-            if (page != null) {
-                page = PageInfo.pageInfo(tasks);
-            }
-        } while (page != null);
-
-        // Save to store
-        this.serverManager().updateServerInfos(serverInfos);
-    }
-
-    protected void executeTasksOnWorker(Id server) {
-        String page = this.supportsPaging() ? PageInfo.PAGE_NONE : null;
-        do {
-            Iterator<HugeTask<Object>> tasks = 
this.tasks(TaskStatus.SCHEDULED, PAGE_SIZE, page,
-                                                          false);
-            while (tasks.hasNext()) {
-                HugeTask<?> task = tasks.next();
-                this.initTaskCallable(task);
-                Id taskServer = task.server();
-                if (taskServer == null) {
-                    LOG.warn("Task '{}' may not be scheduled", task.id());
-                    continue;
-                }
-                HugeTask<?> memTask = this.tasks.get(task.id());
-                if (memTask != null) {
-                    assert memTask.status().code() > task.status().code();
-                    continue;
-                }
-                if (taskServer.equals(server)) {
-                    task.status(TaskStatus.QUEUED);
-                    this.save(task);
-                    this.submitTask(task);
-                }
-            }
-            if (page != null) {
-                page = PageInfo.pageInfo(tasks);
-            }
-        } while (page != null);
-    }
-
-    protected void cancelTasksOnWorker(Id server) {
-        String page = this.supportsPaging() ? PageInfo.PAGE_NONE : null;
-        do {
-            Iterator<HugeTask<Object>> tasks = 
this.tasks(TaskStatus.CANCELLING, PAGE_SIZE, page,
-                                                          false);
-            while (tasks.hasNext()) {
-                HugeTask<?> task = tasks.next();
-                Id taskServer = task.server();
-                if (taskServer == null) {
-                    LOG.warn("Task '{}' may not be scheduled", task.id());
-                    continue;
-                }
-                if (!taskServer.equals(server)) {
-                    continue;
-                }
-                /*
-                 * Task may be loaded from backend store and not initialized.
-                 * like: A task is completed but failed to save in the last
-                 * step, resulting in the status of the task not being
-                 * updated to storage, the task is not in memory, so it's not
-                 * initialized when canceled.
-                 */
-                HugeTask<?> memTask = this.tasks.get(task.id());
-                if (memTask != null) {
-                    task = memTask;
-                } else {
-                    this.initTaskCallable(task);
-                }
-                boolean cancelled = task.cancel(true);
-                LOG.info("Server '{}' cancel task '{}' with cancelled={}",
-                         server, task.id(), cancelled);
-            }
-            if (page != null) {
-                page = PageInfo.pageInfo(tasks);
-            }
-        } while (page != null);
-    }
-
     @Override
     public void taskDone(HugeTask<?> task) {
         this.remove(task);
-
-        Id selfServerId = this.serverManager().selfNodeId();
-        try {
-            this.serverManager().decreaseLoad(task.load());
-        } catch (Throwable e) {
-            LOG.error("Failed to decrease load for task '{}' on server '{}'",
-                      task.id(), selfServerId, e);
-        }
-        LOG.debug("Task '{}' done on server '{}'", task.id(), selfServerId);
+        // Single-node mode: no need to manage load
+        LOG.debug("Task '{}' done", task.id());
     }
 
     protected void remove(HugeTask<?> task) {
@@ -608,6 +459,7 @@ public class StandardTaskScheduler implements TaskScheduler 
{
     public <V> HugeTask<V> delete(Id id, boolean force) {
         this.checkOnMasterNode("delete");
 
+        HugeTask<?> running = this.tasks.get(id);
         HugeTask<?> task = this.task(id, false);
         /*
          * The following is out of date when the task running on worker node:
@@ -619,7 +471,17 @@ public class StandardTaskScheduler implements 
TaskScheduler {
          * in fact, it is also possible to appear on the backend tasks
          * when the database status is inconsistent.
          */
-        if (task != null) {
+        if (running != null) {
+            E.checkArgument(force || running.completed(),
+                            "Can't delete incomplete task '%s' in status %s" +
+                            ", Please try to cancel the task first",
+                            id, running.status());
+            if (force && !running.completed()) {
+                running.overwriteStatus(TaskStatus.DELETING);
+                running.cancel(true);
+            }
+            this.remove(running, force);
+        } else if (task != null) {
             E.checkArgument(force || task.completed(),
                             "Can't delete incomplete task '%s' in status %s" +
                             ", Please try to cancel the task first",
@@ -801,10 +663,9 @@ public class StandardTaskScheduler implements 
TaskScheduler {
         }
     }
 
+    @Deprecated
     private void checkOnMasterNode(String op) {
-        if (!this.serverManager().selfIsMaster()) {
-            throw new HugeException("Can't %s task on non-master server", op);
-        }
+        // Single-node mode: all operations are allowed, no role check needed
     }
 
     private boolean supportsPaging() {
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/TaskAndResultScheduler.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/TaskAndResultScheduler.java
index 26a520bde..70d4d2f57 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/TaskAndResultScheduler.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/TaskAndResultScheduler.java
@@ -46,6 +46,7 @@ import com.google.common.collect.ImmutableMap;
  * Base class of task & result scheduler
  */
 public abstract class TaskAndResultScheduler implements TaskScheduler {
+
     /**
      * Which graph the scheduler belongs to
      */
@@ -61,8 +62,8 @@ public abstract class TaskAndResultScheduler implements 
TaskScheduler {
     private final ServerInfoManager serverManager;
 
     public TaskAndResultScheduler(
-        HugeGraphParams graph,
-        ExecutorService serverInfoDbExecutor) {
+            HugeGraphParams graph,
+            ExecutorService serverInfoDbExecutor) {
         E.checkNotNull(graph, "graph");
 
         this.graph = graph;
@@ -90,7 +91,7 @@ public abstract class TaskAndResultScheduler implements 
TaskScheduler {
         // Save result outcome
         if (rawResult != null) {
             HugeTaskResult result =
-                new HugeTaskResult(HugeTaskResult.genId(task.id()));
+                    new HugeTaskResult(HugeTaskResult.genId(task.id()));
             result.result(rawResult);
 
             this.call(() -> {
@@ -193,7 +194,7 @@ public abstract class TaskAndResultScheduler implements 
TaskScheduler {
             }
             Iterator<Vertex> vertices = this.tx().queryTaskInfos(query);
             Iterator<HugeTask<V>> tasks =
-                new MapperIterator<>(vertices, HugeTask::fromVertex);
+                    new MapperIterator<>(vertices, HugeTask::fromVertex);
             // Convert iterator to list to avoid across thread tx accessed
             return QueryResults.toList(tasks);
         });
@@ -209,16 +210,16 @@ public abstract class TaskAndResultScheduler implements 
TaskScheduler {
 
     protected <V> Iterator<HugeTask<V>> queryTask(List<Id> ids) {
         ListIterator<HugeTask<V>> ts = this.call(
-            () -> {
-                Object[] idArray = ids.toArray(new Id[ids.size()]);
-                Iterator<Vertex> vertices = this.tx()
-                                                .queryTaskInfos(idArray);
-                Iterator<HugeTask<V>> tasks =
-                    new MapperIterator<>(vertices,
-                                         HugeTask::fromVertex);
-                // Convert iterator to list to avoid across thread tx accessed
-                return QueryResults.toList(tasks);
-            });
+                () -> {
+                    Object[] idArray = ids.toArray(new Id[ids.size()]);
+                    Iterator<Vertex> vertices = this.tx()
+                                                    .queryTaskInfos(idArray);
+                    Iterator<HugeTask<V>> tasks =
+                            new MapperIterator<>(vertices,
+                                                 HugeTask::fromVertex);
+                    // Convert iterator to list to avoid across thread tx 
accessed
+                    return QueryResults.toList(tasks);
+                });
 
         Iterator<HugeTaskResult> results = queryTaskResult(ids);
 
@@ -230,7 +231,7 @@ public abstract class TaskAndResultScheduler implements 
TaskScheduler {
 
         return new MapperIterator<>(ts, (task) -> {
             HugeTaskResult taskResult =
-                resultCaches.get(HugeTaskResult.genId(task.id()));
+                    resultCaches.get(HugeTaskResult.genId(task.id()));
             if (taskResult != null) {
                 task.result(taskResult);
             }
@@ -248,6 +249,10 @@ public abstract class TaskAndResultScheduler implements 
TaskScheduler {
             return HugeTask.fromVertex(vertex, false);
         });
 
+        if (result == null) {
+            throw new NotFoundException("Can't find task with id '%s'", id);
+        }
+
         return result;
     }
 
@@ -281,7 +286,7 @@ public abstract class TaskAndResultScheduler implements 
TaskScheduler {
     }
 
     protected <V> Iterator<HugeTask<V>> queryTaskWithoutResult(Map<String,
-        Object> conditions, long limit, String page) {
+            Object> conditions, long limit, String page) {
         return this.call(() -> {
             ConditionQuery query = new ConditionQuery(HugeType.TASK);
             if (page != null) {
@@ -319,7 +324,7 @@ public abstract class TaskAndResultScheduler implements 
TaskScheduler {
     protected HugeTaskResult queryTaskResult(Id taskid) {
         HugeTaskResult result = this.call(() -> {
             Iterator<Vertex> vertices =
-                this.tx().queryTaskInfos(HugeTaskResult.genId(taskid));
+                    this.tx().queryTaskInfos(HugeTaskResult.genId(taskid));
             Vertex vertex = QueryResults.one(vertices);
             if (vertex == null) {
                 return null;
@@ -334,12 +339,12 @@ public abstract class TaskAndResultScheduler implements 
TaskScheduler {
     protected Iterator<HugeTaskResult> queryTaskResult(List<Id> taskIds) {
         return this.call(() -> {
             Object[] idArray =
-                taskIds.stream().map(HugeTaskResult::genId).toArray();
+                    taskIds.stream().map(HugeTaskResult::genId).toArray();
             Iterator<Vertex> vertices = this.tx()
                                             .queryTaskInfos(idArray);
             Iterator<HugeTaskResult> tasks =
-                new MapperIterator<>(vertices,
-                                     HugeTaskResult::fromVertex);
+                    new MapperIterator<>(vertices,
+                                         HugeTaskResult::fromVertex);
             // Convert iterator to list to avoid across thread tx accessed
             return QueryResults.toList(tasks);
         });
diff --git 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/TaskManager.java
 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/TaskManager.java
index 277822a38..ec063754d 100644
--- 
a/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/TaskManager.java
+++ 
b/hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/task/TaskManager.java
@@ -18,7 +18,6 @@
 package org.apache.hugegraph.task;
 
 import java.util.Map;
-import java.util.Queue;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutorService;
@@ -29,11 +28,9 @@ import java.util.concurrent.TimeoutException;
 import org.apache.hugegraph.HugeException;
 import org.apache.hugegraph.HugeGraphParams;
 import org.apache.hugegraph.concurrent.PausableScheduledThreadPool;
-import org.apache.hugegraph.type.define.NodeRole;
 import org.apache.hugegraph.util.Consumers;
 import org.apache.hugegraph.util.E;
 import org.apache.hugegraph.util.ExecutorUtil;
-import org.apache.hugegraph.util.LockUtil;
 import org.apache.hugegraph.util.Log;
 import org.slf4j.Logger;
 
@@ -76,8 +73,6 @@ public final class TaskManager {
     private final ExecutorService ephemeralTaskExecutor;
     private final PausableScheduledThreadPool distributedSchedulerExecutor;
 
-    private boolean enableRoleElected = false;
-
     public static TaskManager instance() {
         return MANAGER;
     }
@@ -102,11 +97,6 @@ public final class TaskManager {
         // For a schedule task to run, just one thread is ok
         this.schedulerExecutor = ExecutorUtil.newPausableScheduledThreadPool(
                 1, TASK_SCHEDULER);
-        // Start after 10x period time waiting for HugeGraphServer startup
-        
this.schedulerExecutor.scheduleWithFixedDelay(this::scheduleOrExecuteJob,
-                                                      10 * SCHEDULE_PERIOD,
-                                                      SCHEDULE_PERIOD,
-                                                      TimeUnit.MILLISECONDS);
     }
 
     public void addScheduler(HugeGraphParams graph) {
@@ -230,14 +220,6 @@ public final class TaskManager {
         }
     }
 
-    public void pauseScheduledThreadPool() {
-        this.schedulerExecutor.pauseSchedule();
-    }
-
-    public void resumeScheduledThreadPool() {
-        this.schedulerExecutor.resumeSchedule();
-    }
-
     public TaskScheduler getScheduler(HugeGraphParams graph) {
         return this.schedulers.get(graph);
     }
@@ -349,125 +331,12 @@ public final class TaskManager {
         return size;
     }
 
-    public void enableRoleElection() {
-        this.enableRoleElected = true;
-    }
-
     public void onAsRoleMaster() {
-        try {
-            for (TaskScheduler entry : this.schedulers.values()) {
-                ServerInfoManager serverInfoManager = entry.serverManager();
-                if (serverInfoManager != null) {
-                    serverInfoManager.changeServerRole(NodeRole.MASTER);
-                } else {
-                    LOG.warn("ServerInfoManager is null for graph {}", 
entry.spaceGraphName());
-                }
-            }
-        } catch (Throwable e) {
-            LOG.error("Exception occurred when change to master role", e);
-            throw e;
-        }
+        // ServerInfo based role propagation is deprecated.
     }
 
     public void onAsRoleWorker() {
-        try {
-            for (TaskScheduler entry : this.schedulers.values()) {
-                ServerInfoManager serverInfoManager = entry.serverManager();
-                if (serverInfoManager != null) {
-                    serverInfoManager.changeServerRole(NodeRole.WORKER);
-                } else {
-                    LOG.warn("ServerInfoManager is null for graph {}", 
entry.spaceGraphName());
-                }
-            }
-        } catch (Throwable e) {
-            LOG.error("Exception occurred when change to worker role", e);
-            throw e;
-        }
-    }
-
-    void notifyNewTask(HugeTask<?> task) {
-        Queue<Runnable> queue = this.schedulerExecutor
-                .getQueue();
-        if (queue.size() <= 1) {
-            /*
-             * Notify to schedule tasks initiatively when have new task
-             * It's OK to not notify again if there are more than one task in
-             * queue(like two, one is timer task, one is immediate task),
-             * we don't want too many immediate tasks to be inserted into 
queue,
-             * one notify will cause all the tasks to be processed.
-             */
-            this.schedulerExecutor.submit(this::scheduleOrExecuteJob);
-        }
-    }
-
-    private void scheduleOrExecuteJob() {
-        // Called by scheduler timer
-        try {
-            for (TaskScheduler entry : this.schedulers.values()) {
-                // Maybe other threads close&remove scheduler at the same time
-                synchronized (entry) {
-                    this.scheduleOrExecuteJobForGraph(entry);
-                }
-            }
-        } catch (Throwable e) {
-            LOG.error("Exception occurred when schedule job", e);
-        }
-    }
-
-    private void scheduleOrExecuteJobForGraph(TaskScheduler scheduler) {
-        E.checkNotNull(scheduler, "scheduler");
-
-        if (scheduler instanceof StandardTaskScheduler) {
-            StandardTaskScheduler standardTaskScheduler = 
(StandardTaskScheduler) (scheduler);
-            ServerInfoManager serverManager = scheduler.serverManager();
-            String spaceGraphName = scheduler.spaceGraphName();
-
-            LockUtil.lock(spaceGraphName, LockUtil.GRAPH_LOCK);
-            try {
-                /*
-                 * Skip if:
-                 * graph is closed (iterate schedulers before graph is closing)
-                 *  or
-                 * graph is not initialized(maybe truncated or cleared).
-                 *
-                 * If graph is closing by other thread, current thread get
-                 * serverManager and try lock graph, at the same time other
-                 * thread deleted the lock-group, current thread would get
-                 * exception 'LockGroup xx does not exists'.
-                 * If graph is closed, don't call serverManager.initialized()
-                 * due to it will reopen graph tx.
-                 */
-                if (!serverManager.graphIsReady()) {
-                    return;
-                }
-
-                // Update server heartbeat
-                serverManager.heartbeat();
-
-                /*
-                 * Master will schedule tasks to suitable servers.
-                 * Note a Worker may become to a Master, so elected-Master 
also needs to
-                 * execute tasks assigned by previous Master when 
enableRoleElected=true.
-                 * However, when enableRoleElected=false, a Master is only set 
by the
-                 * config assignment, assigned-Master always stays the same 
state.
-                 */
-                if (serverManager.selfIsMaster()) {
-                    standardTaskScheduler.scheduleTasksOnMaster();
-                    if (!this.enableRoleElected && 
!serverManager.onlySingleNode()) {
-                        // assigned-Master + non-single-node don't need to 
execute tasks
-                        return;
-                    }
-                }
-
-                // Execute queued tasks scheduled to current server
-                
standardTaskScheduler.executeTasksOnWorker(serverManager.selfNodeId());
-
-                // Cancel tasks scheduled to current server
-                
standardTaskScheduler.cancelTasksOnWorker(serverManager.selfNodeId());
-            } finally {
-                LockUtil.unlock(spaceGraphName, LockUtil.GRAPH_LOCK);
-            }
-        }
+        // ServerInfo based role propagation is deprecated.
     }
 
     private static final ThreadLocal<String> CONTEXTS = new ThreadLocal<>();
diff --git 
a/hugegraph-server/hugegraph-dist/src/assembly/static/conf/graphs/hstore.properties.template
 
b/hugegraph-server/hugegraph-dist/src/assembly/static/conf/graphs/hstore.properties.template
index f627b6202..4c78cad66 100644
--- 
a/hugegraph-server/hugegraph-dist/src/assembly/static/conf/graphs/hstore.properties.template
+++ 
b/hugegraph-server/hugegraph-dist/src/assembly/static/conf/graphs/hstore.properties.template
@@ -33,7 +33,6 @@ store=hugegraph
 pd.peers=127.0.0.1:8686
 
 # task config
-task.scheduler_type=local
 task.schedule_period=10
 task.retry=0
 task.wait_timeout=10
diff --git 
a/hugegraph-server/hugegraph-dist/src/assembly/static/conf/graphs/hugegraph.properties
 
b/hugegraph-server/hugegraph-dist/src/assembly/static/conf/graphs/hugegraph.properties
index bc15c39b3..26adfe018 100644
--- 
a/hugegraph-server/hugegraph-dist/src/assembly/static/conf/graphs/hugegraph.properties
+++ 
b/hugegraph-server/hugegraph-dist/src/assembly/static/conf/graphs/hugegraph.properties
@@ -32,7 +32,6 @@ store=hugegraph
 #pd.peers=127.0.0.1:8686
 
 # task config
-task.scheduler_type=local
 task.schedule_period=10
 task.retry=0
 task.wait_timeout=10
diff --git 
a/hugegraph-server/hugegraph-dist/src/assembly/static/conf/rest-server.properties
 
b/hugegraph-server/hugegraph-dist/src/assembly/static/conf/rest-server.properties
index bbb956aaf..33ff0effc 100644
--- 
a/hugegraph-server/hugegraph-dist/src/assembly/static/conf/rest-server.properties
+++ 
b/hugegraph-server/hugegraph-dist/src/assembly/static/conf/rest-server.properties
@@ -23,9 +23,6 @@ arthas.disabled_commands=jad
 #auth.admin_pa=pa
 #auth.graph_store=hugegraph
 
-# lightweight load balancing (TODO: legacy mode, remove soon)
-server.id=server-1
-server.role=master
 # use pd
 # usePD=true
 
diff --git 
a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/MultiGraphsTest.java
 
b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/MultiGraphsTest.java
index 4fae0f76c..2c9c11021 100644
--- 
a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/MultiGraphsTest.java
+++ 
b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/MultiGraphsTest.java
@@ -248,7 +248,7 @@ public class MultiGraphsTest extends BaseCoreTest {
 
     @Test
     public void testCreateGraphsWithSameName() {
-        List<HugeGraph> graphs = openGraphs("g", "g", "G");
+        List<HugeGraph> graphs = openGraphs("gg", "gg", "GG");
         HugeGraph g1 = graphs.get(0);
         HugeGraph g2 = graphs.get(1);
         HugeGraph g3 = graphs.get(2);
@@ -320,6 +320,14 @@ public class MultiGraphsTest extends BaseCoreTest {
         destroyGraphs(ImmutableList.of(g1, g2, graph));
     }
 
+    @Test
+    public void testOpenGraphWithDeprecatedTaskSchedulerType() {
+        HugeGraph graph = openGraphWithBackend("legacySchedulerType",
+                                               "rocksdb", "binary",
+                                               "task.scheduler_type", "local");
+        destroyGraphs(ImmutableList.of(graph));
+    }
+
     @Test
     public void testCreateGraphsWithMultiDisksForRocksDB() {
         HugeGraph g1 = openGraphWithBackend("g1", "rocksdb", "binary", 
"rocksdb.data_disks",
diff --git 
a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/TaskCoreTest.java
 
b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/TaskCoreTest.java
index 2d106fc3b..9e8269268 100644
--- 
a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/TaskCoreTest.java
+++ 
b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/core/TaskCoreTest.java
@@ -17,9 +17,15 @@
 
 package org.apache.hugegraph.core;
 
-import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
 import java.util.Random;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
 import org.apache.hugegraph.HugeException;
@@ -33,6 +39,7 @@ import org.apache.hugegraph.job.EphemeralJobBuilder;
 import org.apache.hugegraph.job.GremlinJob;
 import org.apache.hugegraph.job.JobBuilder;
 import org.apache.hugegraph.task.HugeTask;
+import org.apache.hugegraph.task.StandardTaskScheduler;
 import org.apache.hugegraph.task.TaskCallable;
 import org.apache.hugegraph.task.TaskScheduler;
 import org.apache.hugegraph.task.TaskStatus;
@@ -53,11 +60,73 @@ public class TaskCoreTest extends BaseCoreTest {
 
         HugeGraph graph = graph();
         TaskScheduler scheduler = graph.taskScheduler();
+        this.clearTasks(scheduler);
+    }
+
+    private void clearTasks(TaskScheduler scheduler) {
+        for (int pass = 0; pass < 3; pass++) {
+            List<HugeTask<Object>> tasks = listTasks(scheduler);
+            if (tasks.isEmpty()) {
+                return;
+            }
+
+            for (HugeTask<Object> task : tasks) {
+                if (!task.completed() && task.status() != TaskStatus.DELETING) 
{
+                    scheduler.cancel(task);
+                }
+            }
+
+            try {
+                scheduler.waitUntilAllTasksCompleted(10);
+            } catch (TimeoutException ignored) {
+                // Delete below will either remove completed tasks or fail 
loudly.
+            }
+
+            for (HugeTask<Object> task : listTasks(scheduler)) {
+                deleteTaskAndWaitGone(scheduler, task.id());
+            }
+        }
 
+        List<HugeTask<Object>> remaining = listTasks(scheduler);
+        if (!remaining.isEmpty()) {
+            Assert.fail(String.format("Failed to clean tasks: %s", remaining));
+        }
+    }
+
+    private static List<HugeTask<Object>> listTasks(TaskScheduler scheduler) {
+        List<HugeTask<Object>> tasks = new ArrayList<>();
         Iterator<HugeTask<Object>> iter = scheduler.tasks(null, -1, null);
         while (iter.hasNext()) {
-            scheduler.delete(iter.next().id(), false);
+            tasks.add(iter.next());
+        }
+        return tasks;
+    }
+
+    private static void waitUntilTaskRunning(TaskScheduler scheduler) {
+        for (int pass = 0; pass < 1000; pass++) {
+            if (scheduler.pendingTasks() > 0) {
+                return;
+            }
+            sleepAWhile(10L);
+        }
+        Assert.fail("Timed out waiting for task to start running");
+    }
+
+    private static void deleteTaskAndWaitGone(TaskScheduler scheduler, Id id) {
+        for (int pass = 0; pass < 30; pass++) {
+            try {
+                scheduler.delete(id, true);
+            } catch (NotFoundException ignored) {
+                return;
+            }
+            try {
+                scheduler.task(id);
+            } catch (NotFoundException ignored) {
+                return;
+            }
+            sleepAWhile(100L);
         }
+        Assert.fail(String.format("Failed to delete task '%s'", id));
     }
 
     @Test
@@ -76,12 +145,15 @@ public class TaskCoreTest extends BaseCoreTest {
         Assert.assertEquals(id, task.id());
         Assert.assertFalse(task.completed());
 
-        Assert.assertThrows(IllegalArgumentException.class, () -> {
-            scheduler.delete(id, false);
-        }, e -> {
-            Assert.assertContains("Can't delete incomplete task '88888'",
-                                  e.getMessage());
-        });
+        if (scheduler instanceof StandardTaskScheduler) {
+            // StandardTaskScheduler: delete of incomplete task throws
+            Assert.assertThrows(IllegalArgumentException.class, () -> {
+                scheduler.delete(id, false);
+            }, e -> {
+                Assert.assertContains("Can't delete incomplete task '88888'",
+                                      e.getMessage());
+            });
+        }
 
         task = scheduler.waitUntilTaskCompleted(task.id(), 10);
         Assert.assertEquals(id, task.id());
@@ -89,7 +161,7 @@ public class TaskCoreTest extends BaseCoreTest {
         Assert.assertEquals(TaskStatus.SUCCESS, task.status());
 
         Assert.assertEquals("test-task", scheduler.task(id).name());
-        Assert.assertEquals("test-task", scheduler.tasks(Arrays.asList(id))
+        Assert.assertEquals("test-task", scheduler.tasks(List.of(id))
                                                   .next().name());
 
         Iterator<HugeTask<Object>> iter = 
scheduler.tasks(ImmutableList.of(id));
@@ -115,6 +187,249 @@ public class TaskCoreTest extends BaseCoreTest {
         });
     }
 
+    @Test
+    public void testScheduleDoesNotPersistTaskWhenQueueFull() {
+        HugeGraph graph = graph();
+        TaskScheduler scheduler = graph.taskScheduler();
+        if (!(scheduler instanceof StandardTaskScheduler)) {
+            return;
+        }
+
+        @SuppressWarnings("unchecked")
+        Map<Id, HugeTask<?>> tasks = Whitebox.getInternalState(scheduler,
+                                                               "tasks");
+        List<Id> placeholderIds = new ArrayList<>();
+        Id id = IdGenerator.of(999996);
+        try {
+            for (int i = 0; tasks.size() < TaskScheduler.MAX_PENDING_TASKS; 
i++) {
+                Id placeholderId = IdGenerator.of(880000 + i);
+                tasks.put(placeholderId, new HugeTask<>(placeholderId, null,
+                                                        new 
SleepCallable<>()));
+                placeholderIds.add(placeholderId);
+            }
+
+            HugeTask<?> task = new HugeTask<>(id, null, new SleepCallable<>());
+            task.type("test");
+            task.name("queue-full-task");
+
+            Assert.assertThrows(IllegalArgumentException.class, () -> {
+                scheduler.schedule(task);
+            }, e -> {
+                Assert.assertContains("Pending tasks size", e.getMessage());
+            });
+            Assert.assertThrows(NotFoundException.class, () -> {
+                scheduler.task(id);
+            });
+        } finally {
+            for (Id placeholderId : placeholderIds) {
+                tasks.remove(placeholderId);
+            }
+            tasks.remove(id);
+        }
+    }
+
+    @Test
+    public void testDeleteIncompleteTask() {
+        HugeGraph graph = graph();
+        TaskScheduler scheduler = graph.taskScheduler();
+
+        Id id = IdGenerator.of(88891);
+        HugeTask<?> task = new HugeTask<>(id, null, new SleepCallable<>());
+        task.type("test");
+        task.name("delete-incomplete-task");
+        scheduler.schedule(task);
+
+        try {
+            if (scheduler instanceof StandardTaskScheduler) {
+                Assert.assertThrows(IllegalArgumentException.class, () -> {
+                    scheduler.delete(id, false);
+                }, e -> {
+                    Assert.assertContains("Can't delete incomplete task 
'88891'",
+                                          e.getMessage());
+                });
+            } else {
+                waitUntilTaskRunning(scheduler);
+                HugeTask<?> deleted = scheduler.delete(id, false);
+                Assert.assertNotNull(deleted);
+                Assert.assertEquals(TaskStatus.DELETING, deleted.status());
+                Assert.assertEquals(TaskStatus.DELETING, 
scheduler.task(id).status());
+            }
+        } finally {
+            try {
+                scheduler.waitUntilAllTasksCompleted(10);
+            } catch (TimeoutException ignored) {
+                // Force cleanup below handles non-interruptible test tasks.
+            }
+            deleteTaskAndWaitGone(scheduler, id);
+        }
+    }
+
+    @Test
+    public void testForceDeleteRunningTaskDoesNotResurrectAfterDone()
+            throws Exception {
+        HugeGraph graph = graph();
+        TaskScheduler scheduler = graph.taskScheduler();
+        if (!(scheduler instanceof StandardTaskScheduler)) {
+            return;
+        }
+
+        Id id = IdGenerator.of(88897);
+        BlockingCallable.reset();
+        HugeTask<?> task = new HugeTask<>(id, null, new BlockingCallable<>());
+        task.type("test");
+        task.name("force-delete-running-task");
+        Future<?> future = null;
+
+        try {
+            future = scheduler.schedule(task);
+            waitUntilTaskRunning(scheduler);
+            Assert.assertTrue(BlockingCallable.awaitStarted());
+
+            HugeTask<?> deleted = scheduler.delete(id, true);
+            Assert.assertNotNull(deleted);
+            Assert.assertThrows(NotFoundException.class, () -> {
+                scheduler.task(id);
+            });
+
+            BlockingCallable.release();
+            try {
+                future.get(10L, TimeUnit.SECONDS);
+            } catch (CancellationException ignored) {
+                // Expected after deleting a locally running task.
+            }
+
+            Assert.assertThrows(NotFoundException.class, () -> {
+                scheduler.task(id);
+            });
+        } finally {
+            BlockingCallable.release();
+            if (future != null && !future.isDone()) {
+                future.cancel(true);
+            }
+            deleteTaskAndWaitGone(scheduler, id);
+        }
+    }
+
+    @Test
+    public void testDeleteRemoteLockedIncompleteTaskFailsFast() {
+        HugeGraph graph = graph();
+        TaskScheduler scheduler = graph.taskScheduler();
+        if (scheduler instanceof StandardTaskScheduler) {
+            return;
+        }
+
+        Id id = IdGenerator.of(88892);
+        BlockingCallable.reset();
+        HugeTask<?> task = new HugeTask<>(id, null, new BlockingCallable<>());
+        task.type("test");
+        task.name("delete-remote-locked-incomplete-task");
+        scheduler.schedule(task);
+
+        Map<Id, HugeTask<?>> runningTasks =
+                Whitebox.getInternalState(scheduler, "runningTasks");
+        HugeTask<?> running = null;
+        try {
+            waitUntilTaskRunning(scheduler);
+            Assert.assertTrue(BlockingCallable.awaitStarted());
+            running = runningTasks.remove(id);
+            Assert.assertNotNull(running);
+
+            Assert.assertThrows(IllegalStateException.class, () -> {
+                scheduler.delete(id, false);
+            }, e -> {
+                Assert.assertContains("locked by another server", 
e.getMessage());
+            });
+            Assert.assertThrows(IllegalStateException.class, () -> {
+                scheduler.delete(id, true);
+            }, e -> {
+                Assert.assertContains("locked by another server", 
e.getMessage());
+            });
+            Assert.assertNotEquals(TaskStatus.DELETING, 
scheduler.task(id).status());
+        } finally {
+            if (running != null && !running.completed()) {
+                runningTasks.put(id, running);
+            }
+            BlockingCallable.release();
+            try {
+                scheduler.waitUntilAllTasksCompleted(10);
+            } catch (TimeoutException ignored) {
+                // Force cleanup below handles non-interruptible test tasks.
+            }
+            deleteTaskAndWaitGone(scheduler, id);
+        }
+    }
+
+    @Test
+    public void testForceDeleteRunningDistributedTaskWaitsForRunnerExit() {
+        HugeGraph graph = graph();
+        TaskScheduler scheduler = graph.taskScheduler();
+        if (scheduler instanceof StandardTaskScheduler) {
+            return;
+        }
+
+        Id id = IdGenerator.of(88895);
+        BlockingCallable.reset();
+        HugeTask<?> task = new HugeTask<>(id, null, new BlockingCallable<>());
+        task.type("test");
+        task.name("force-delete-running-distributed-task");
+        scheduler.schedule(task);
+
+        try {
+            waitUntilTaskRunning(scheduler);
+            Assert.assertTrue(BlockingCallable.awaitStarted());
+
+            HugeTask<?> deleted = scheduler.delete(id, true);
+            Assert.assertNotNull(deleted);
+            Assert.assertEquals(TaskStatus.DELETING, deleted.status());
+            Assert.assertEquals(TaskStatus.DELETING, 
scheduler.task(id).status());
+        } finally {
+            BlockingCallable.release();
+            try {
+                scheduler.waitUntilAllTasksCompleted(10);
+            } catch (TimeoutException ignored) {
+                // Force cleanup below handles non-interruptible test tasks.
+            }
+            deleteTaskAndWaitGone(scheduler, id);
+        }
+    }
+
+    @Test
+    public void testLegacyTaskStatusesAreNotRestored() {
+        HugeGraph graph = graph();
+        TaskScheduler scheduler = graph.taskScheduler();
+        if (!(scheduler instanceof StandardTaskScheduler)) {
+            return;
+        }
+
+        Id schedulingId = IdGenerator.of(88893);
+        Id scheduledId = IdGenerator.of(88894);
+        HugeTask<?> scheduling = new HugeTask<>(schedulingId, null,
+                                                new SleepCallable<>());
+        scheduling.type("test");
+        scheduling.name("legacy-scheduling-task");
+        scheduling.overwriteStatus(TaskStatus.SCHEDULING);
+        HugeTask<?> scheduled = new HugeTask<>(scheduledId, null,
+                                               new SleepCallable<>());
+        scheduled.type("test");
+        scheduled.name("legacy-scheduled-task");
+        scheduled.overwriteStatus(TaskStatus.SCHEDULED);
+
+        try {
+            scheduler.save(scheduling);
+            scheduler.save(scheduled);
+            scheduler.restoreTasks();
+
+            Assert.assertEquals(0, scheduler.pendingTasks());
+            Assert.assertEquals(TaskStatus.SCHEDULING,
+                                scheduler.task(schedulingId).status());
+            Assert.assertEquals(TaskStatus.SCHEDULED,
+                                scheduler.task(scheduledId).status());
+        } finally {
+            deleteTaskAndWaitGone(scheduler, schedulingId);
+            deleteTaskAndWaitGone(scheduler, scheduledId);
+        }
+    }
+
     @Test
     public void testTaskWithoutResult() throws TimeoutException {
         HugeGraph graph = graph();
@@ -164,7 +479,7 @@ public class TaskCoreTest extends BaseCoreTest {
         Assert.assertEquals("metadata-task", taskWithoutResult.name());
         Assert.assertNull(taskWithoutResult.result());
 
-        Iterator<HugeTask<Object>> iter = 
scheduler.tasks(ImmutableList.of(id));
+        Iterator<HugeTask<Object>> iter = 
scheduler.tasks(ImmutableList.of(id), true);
         Assert.assertTrue(iter.hasNext());
         taskWithResult = iter.next();
         Assert.assertEquals("metadata-task", taskWithResult.name());
@@ -184,7 +499,7 @@ public class TaskCoreTest extends BaseCoreTest {
         Assert.assertEquals("metadata-task", taskWithoutResult.name());
         Assert.assertNull(taskWithoutResult.result());
 
-        iter = scheduler.tasks(TaskStatus.SUCCESS, 10, null);
+        iter = scheduler.tasks(TaskStatus.SUCCESS, 10, null, true);
         Assert.assertTrue(iter.hasNext());
         taskWithResult = iter.next();
         Assert.assertEquals("metadata-task", taskWithResult.name());
@@ -278,13 +593,18 @@ public class TaskCoreTest extends BaseCoreTest {
         Assert.assertEquals("test", task.type());
         Assert.assertFalse(task.completed());
 
-        HugeTask<?> task2 = scheduler.waitUntilTaskCompleted(task.id(), 10);
+        // Ephemeral tasks are node-local and not persisted to DB.
+        // Use Future.get() to wait for completion instead of ID-based lookup.
+        try {
+            task.get(10, java.util.concurrent.TimeUnit.SECONDS);
+        } catch (Exception e) {
+            throw new RuntimeException("Ephemeral task execution failed", e);
+        }
+
         Assert.assertEquals(TaskStatus.SUCCESS, task.status());
         Assert.assertEquals("{\"k1\":13579,\"k2\":\"24680\"}", task.result());
 
-        Assert.assertEquals(TaskStatus.SUCCESS, task2.status());
-        Assert.assertEquals("{\"k1\":13579,\"k2\":\"24680\"}", task2.result());
-
+        // Ephemeral tasks are not stored in DB, so these should throw 
NotFoundException
         Assert.assertThrows(NotFoundException.class, () -> {
             scheduler.waitUntilTaskCompleted(task.id(), 10);
         });
@@ -639,7 +959,12 @@ public class TaskCoreTest extends BaseCoreTest {
         scheduler.cancel(task);
 
         task = scheduler.task(task.id());
-        Assert.assertEquals(TaskStatus.CANCELLING, task.status());
+        // For DistributedTaskScheduler, local cancel may result in CANCELLED 
directly
+        // (task thread updates status after being interrupted)
+        // or CANCELLING (if task hasn't processed the interrupt yet)
+        Assert.assertTrue("Task status should be CANCELLING or CANCELLED, but 
was " + task.status(),
+                          task.status() == TaskStatus.CANCELLING ||
+                          task.status() == TaskStatus.CANCELLED);
 
         task = scheduler.waitUntilTaskCompleted(task.id(), 10);
         Assert.assertEquals(TaskStatus.CANCELLED, task.status());
@@ -711,46 +1036,60 @@ public class TaskCoreTest extends BaseCoreTest {
         scheduler.cancel(task);
 
         task = scheduler.task(task.id());
-        Assert.assertEquals(TaskStatus.CANCELLING, task.status());
+        Assert.assertTrue("Task status should be CANCELLING or CANCELLED, but 
was " + task.status(),
+                          task.status() == TaskStatus.CANCELLING ||
+                          task.status() == TaskStatus.CANCELLED);
 
         task = scheduler.waitUntilTaskCompleted(task.id(), 10);
         Assert.assertEquals(TaskStatus.CANCELLED, task.status());
         Assert.assertTrue("progress=" + task.progress(),
                           0 < task.progress() && task.progress() < 10);
         Assert.assertEquals(0, task.retries());
-        Assert.assertEquals(null, task.result());
+        Assert.assertNull(task.result());
 
         HugeTask<Object> finalTask = task;
-        Assert.assertThrows(IllegalArgumentException.class, () -> {
-            Whitebox.invoke(scheduler.getClass(), "restore", scheduler,
-                            finalTask);
-        }, e -> {
-            Assert.assertContains("No need to restore completed task",
-                                  e.getMessage());
-        });
-
-        HugeTask<Object> task2 = scheduler.task(task.id());
-        Assert.assertThrows(IllegalArgumentException.class, () -> {
-            Whitebox.invoke(scheduler.getClass(), "restore", scheduler, task2);
-        }, e -> {
-            Assert.assertContains("No need to restore completed task",
-                                  e.getMessage());
-        });
-
-        Whitebox.setInternalState(task2, "status", TaskStatus.RUNNING);
-        Whitebox.invoke(scheduler.getClass(), "restore", scheduler, task2);
 
-        Assert.assertThrows(IllegalArgumentException.class, () -> {
+        // because Distributed do nothing in restore
+        if (scheduler instanceof StandardTaskScheduler) {
+            Assert.assertThrows(IllegalArgumentException.class, () -> {
+                Whitebox.invoke(scheduler.getClass(), "restore", scheduler,
+                                finalTask);
+            }, e -> {
+                Assert.assertContains("No need to restore completed task",
+                                      e.getMessage());
+            });
+
+            HugeTask<Object> task2 = scheduler.task(task.id());
+            Assert.assertThrows(IllegalArgumentException.class, () -> {
+                Whitebox.invoke(scheduler.getClass(), "restore", scheduler, 
task2);
+            }, e -> {
+                Assert.assertContains("No need to restore completed task",
+                                      e.getMessage());
+            });
+
+            Whitebox.setInternalState(task2, "status", TaskStatus.RUNNING);
             Whitebox.invoke(scheduler.getClass(), "restore", scheduler, task2);
-        }, e -> {
-            Assert.assertContains("is already in the queue", e.getMessage());
-        });
 
-        scheduler.waitUntilTaskCompleted(task2.id(), 10);
-        sleepAWhile(500);
-        Assert.assertEquals(10, task2.progress());
-        Assert.assertEquals(1, task2.retries());
-        Assert.assertEquals("100", task2.result());
+            Assert.assertThrows(IllegalArgumentException.class, () -> {
+                Whitebox.invoke(scheduler.getClass(), "restore", scheduler, 
task2);
+            }, e -> {
+                Assert.assertContains("is already in the queue", 
e.getMessage());
+            });
+            scheduler.waitUntilTaskCompleted(task2.id(), 10);
+            sleepAWhile(500);
+            Assert.assertEquals(10, task2.progress());
+            Assert.assertEquals(1, task2.retries());
+            Assert.assertEquals("100", task2.result());
+        } else {
+            // DistributedTaskScheduler.restoreTasks() is a no-op by design —
+            // distributed recovery is handled by cronSchedule(), not
+            // restoreTasks(). Verify it does not throw and leaves task state
+            // untouched.
+            scheduler.restoreTasks();
+            HugeTask<?> recovered = scheduler.task(task.id());
+            Assert.assertNotNull(recovered);
+            Assert.assertEquals(TaskStatus.CANCELLED, recovered.status());
+        }
     }
 
     private HugeTask<Object> runGremlinJob(String gremlin) {
@@ -779,6 +1118,46 @@ public class TaskCoreTest extends BaseCoreTest {
         }
     }
 
+    public static class BlockingCallable<V> extends TaskCallable<V> {
+
+        private static volatile CountDownLatch started = new CountDownLatch(1);
+        private static volatile CountDownLatch release = new CountDownLatch(1);
+
+        public BlockingCallable() {
+            // pass
+        }
+
+        public static void reset() {
+            started = new CountDownLatch(1);
+            release = new CountDownLatch(1);
+        }
+
+        public static boolean awaitStarted() {
+            try {
+                return started.await(10L, TimeUnit.SECONDS);
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                return false;
+            }
+        }
+
+        public static void release() {
+            release.countDown();
+        }
+
+        @Override
+        public V call() throws Exception {
+            started.countDown();
+            release.await(10L, TimeUnit.SECONDS);
+            return null;
+        }
+
+        @Override
+        public void done() {
+            this.graph().taskScheduler().save(this.task());
+        }
+    }
+
     public static class SleepCallable<V> extends TaskCallable<V> {
 
         public SleepCallable() {
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 2bb10efaf..f7b2729fe 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
@@ -50,6 +50,7 @@ import org.apache.hugegraph.unit.core.SecurityManagerTest;
 import org.apache.hugegraph.unit.core.SerialEnumTest;
 import org.apache.hugegraph.unit.core.ServerInfoManagerTest;
 import org.apache.hugegraph.unit.core.SystemSchemaStoreTest;
+import org.apache.hugegraph.unit.core.TaskSchedulerServerInfoTest;
 import org.apache.hugegraph.unit.core.TraversalUtilTest;
 import org.apache.hugegraph.unit.id.EdgeIdTest;
 import org.apache.hugegraph.unit.id.IdTest;
@@ -134,6 +135,7 @@ import org.junit.runners.Suite;
         PageStateTest.class,
         SystemSchemaStoreTest.class,
         ServerInfoManagerTest.class,
+        TaskSchedulerServerInfoTest.class,
         RoleElectionStateMachineTest.class,
         HugeGraphAuthProxyTest.class,
         SchemaElementTest.class,
diff --git 
a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/core/ServerInfoManagerTest.java
 
b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/core/ServerInfoManagerTest.java
index 85815bbc1..607d81de9 100644
--- 
a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/core/ServerInfoManagerTest.java
+++ 
b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/core/ServerInfoManagerTest.java
@@ -50,6 +50,20 @@ public class ServerInfoManagerTest {
         this.hugegraphManager = new ServerInfoManager(hugegraphParams, 
executor);
     }
 
+    @Test
+    public void testInitDoesNotAccessBackendStore() {
+        HugeGraphParams graphParams = Mockito.mock(HugeGraphParams.class);
+        ExecutorService executor = Mockito.mock(ExecutorService.class);
+        ServerInfoManager manager = new ServerInfoManager(graphParams, 
executor);
+
+        manager.init();
+
+        Mockito.verify(graphParams, Mockito.never()).systemTransaction();
+        Mockito.verify(graphParams, Mockito.never()).backendStoreFeatures();
+        Mockito.verify(graphParams, Mockito.never()).graph();
+        Mockito.verify(graphParams, Mockito.never()).closeTx();
+    }
+
     @Test
     public void testSelfNodeIdScopedByGraphWithSameNodeId() {
         GlobalMasterInfo nodeInfo = GlobalMasterInfo.master("server-1");
@@ -73,4 +87,22 @@ public class ServerInfoManagerTest {
     public void testSelfNodeIdReturnsNullWhenNotInitialized() {
         Assert.assertNull(this.sysGraphManager.selfNodeId());
     }
+
+    @Test
+    public void testSelfNodeIdReturnsNullWhenNodeIdMissing() {
+        Whitebox.setInternalState(this.sysGraphManager,
+                                  "globalNodeInfo", new GlobalMasterInfo());
+
+        Assert.assertNull(this.sysGraphManager.selfNodeId());
+    }
+
+    @Test
+    public void testInitServerInfoDoesNotAccessBackendStore() {
+        GlobalMasterInfo nodeInfo = GlobalMasterInfo.master("server-1");
+
+        this.sysGraphManager.initServerInfo(nodeInfo);
+
+        Assert.assertEquals("DEFAULT-~sys_graph/server-1",
+                            this.sysGraphManager.selfNodeId().asString());
+    }
 }
diff --git 
a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/core/TaskSchedulerServerInfoTest.java
 
b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/core/TaskSchedulerServerInfoTest.java
new file mode 100644
index 000000000..758b8c1f2
--- /dev/null
+++ 
b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/core/TaskSchedulerServerInfoTest.java
@@ -0,0 +1,219 @@
+/*
+ * 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.unit.core;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import org.apache.commons.configuration2.PropertiesConfiguration;
+import org.apache.hugegraph.HugeGraph;
+import org.apache.hugegraph.HugeGraphParams;
+import org.apache.hugegraph.backend.id.Id;
+import org.apache.hugegraph.backend.id.IdGenerator;
+import org.apache.hugegraph.concurrent.PausableScheduledThreadPool;
+import org.apache.hugegraph.config.CoreOptions;
+import org.apache.hugegraph.config.HugeConfig;
+import org.apache.hugegraph.config.ServerOptions;
+import org.apache.hugegraph.core.GraphManager;
+import org.apache.hugegraph.event.EventHub;
+import org.apache.hugegraph.exception.NotFoundException;
+import org.apache.hugegraph.task.DistributedTaskScheduler;
+import org.apache.hugegraph.task.HugeTask;
+import org.apache.hugegraph.task.TaskCallable;
+import org.apache.hugegraph.task.TaskStatus;
+import org.apache.hugegraph.testutil.Assert;
+import org.apache.hugegraph.testutil.Whitebox;
+import org.apache.hugegraph.util.ExecutorUtil;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+public class TaskSchedulerServerInfoTest {
+
+    @Test
+    public void testDistributedCheckRequirementDoesNotNeedServerInfo() {
+        HugeGraph graph = Mockito.mock(HugeGraph.class);
+        Mockito.when(graph.graphSpace()).thenReturn("DEFAULT");
+
+        HugeGraphParams params = Mockito.mock(HugeGraphParams.class);
+        Mockito.when(params.graph()).thenReturn(graph);
+        Mockito.when(params.name()).thenReturn("hugegraph");
+        Mockito.when(params.spaceGraphName()).thenReturn("DEFAULT-hugegraph");
+        Mockito.when(params.configuration()).thenReturn(newConfig());
+
+        PausableScheduledThreadPool schedulerExecutor =
+                ExecutorUtil.newPausableScheduledThreadPool(
+                        1, "distributed-scheduler-test-%d");
+        ExecutorService taskDbExecutor = Executors.newSingleThreadExecutor();
+        ExecutorService schemaTaskExecutor = 
Executors.newSingleThreadExecutor();
+        ExecutorService olapTaskExecutor = Executors.newSingleThreadExecutor();
+        ExecutorService gremlinTaskExecutor = 
Executors.newSingleThreadExecutor();
+        ExecutorService ephemeralTaskExecutor = 
Executors.newSingleThreadExecutor();
+        ExecutorService serverInfoDbExecutor = 
Executors.newSingleThreadExecutor();
+
+        try {
+            DistributedTaskScheduler scheduler = new DistributedTaskScheduler(
+                    params, schedulerExecutor, taskDbExecutor, 
schemaTaskExecutor,
+                    olapTaskExecutor, gremlinTaskExecutor, 
ephemeralTaskExecutor,
+                    serverInfoDbExecutor);
+            scheduler.checkRequirement("schedule");
+        } finally {
+            schedulerExecutor.shutdownNow();
+            taskDbExecutor.shutdownNow();
+            schemaTaskExecutor.shutdownNow();
+            olapTaskExecutor.shutdownNow();
+            gremlinTaskExecutor.shutdownNow();
+            ephemeralTaskExecutor.shutdownNow();
+            serverInfoDbExecutor.shutdownNow();
+        }
+    }
+
+    @Test
+    public void testDistributedCancelTreatsMissingRetryTaskAsGone() {
+        HugeGraph graph = Mockito.mock(HugeGraph.class);
+        Mockito.when(graph.graphSpace()).thenReturn("DEFAULT");
+
+        HugeGraphParams params = Mockito.mock(HugeGraphParams.class);
+        Mockito.when(params.graph()).thenReturn(graph);
+        Mockito.when(params.name()).thenReturn("hugegraph");
+        Mockito.when(params.spaceGraphName()).thenReturn("DEFAULT-hugegraph");
+        Mockito.when(params.configuration()).thenReturn(newConfig());
+
+        PausableScheduledThreadPool schedulerExecutor =
+                ExecutorUtil.newPausableScheduledThreadPool(
+                        1, "distributed-cancel-test-%d");
+        ExecutorService taskDbExecutor = Executors.newSingleThreadExecutor();
+        ExecutorService schemaTaskExecutor = 
Executors.newSingleThreadExecutor();
+        ExecutorService olapTaskExecutor = Executors.newSingleThreadExecutor();
+        ExecutorService gremlinTaskExecutor = 
Executors.newSingleThreadExecutor();
+        ExecutorService ephemeralTaskExecutor = 
Executors.newSingleThreadExecutor();
+        ExecutorService serverInfoDbExecutor = 
Executors.newSingleThreadExecutor();
+
+        try {
+            DistributedTaskScheduler scheduler = new DistributedTaskScheduler(
+                    params, schedulerExecutor, taskDbExecutor, 
schemaTaskExecutor,
+                    olapTaskExecutor, gremlinTaskExecutor, 
ephemeralTaskExecutor,
+                    serverInfoDbExecutor) {
+
+                @Override
+                protected boolean updateStatus(Id id, TaskStatus prestatus,
+                                               TaskStatus status) {
+                    return false;
+                }
+
+                @Override
+                protected <V> HugeTask<V> taskWithoutResult(Id id) {
+                    throw new NotFoundException("Can't find task with id 
'%s'", id);
+                }
+            };
+            Id id = IdGenerator.of(999997);
+            HugeTask<?> task = new HugeTask<>(id, null, new 
TaskCallable<Object>() {
+                @Override
+                public Object call() {
+                    return null;
+                }
+            });
+            task.type("test");
+            task.name("missing-retry-task");
+
+            scheduler.cancel(task);
+        } finally {
+            schedulerExecutor.shutdownNow();
+            taskDbExecutor.shutdownNow();
+            schemaTaskExecutor.shutdownNow();
+            olapTaskExecutor.shutdownNow();
+            gremlinTaskExecutor.shutdownNow();
+            ephemeralTaskExecutor.shutdownNow();
+            serverInfoDbExecutor.shutdownNow();
+        }
+    }
+
+    @Test
+    public void testGraphManagerDoesNotGenerateServerIdWhenElectionDisabled() {
+        HugeConfig config = newConfig();
+
+        GraphManager manager = new GraphManager(config, new EventHub("test"));
+        try {
+            Assert.assertEquals("", config.get(ServerOptions.SERVER_ID));
+            Assert.assertNull(manager.globalNodeRoleInfo().nodeId());
+        } finally {
+            manager.close();
+        }
+    }
+
+    @Test
+    public void testGraphManagerWarnsOnRoleElection() {
+        PropertiesConfiguration conf = new PropertiesConfiguration();
+        conf.setProperty(ServerOptions.ENABLE_SERVER_ROLE_ELECTION.name(), 
true);
+        HugeConfig config = new HugeConfig(conf);
+
+        GraphManager manager = new GraphManager(config, new EventHub("test"));
+        try {
+            Assert.assertNotNull(manager);
+        } finally {
+            manager.close();
+        }
+    }
+
+    @Test
+    public void testGraphManagerDoesNotInjectPdPeersForStandaloneRocksDB() {
+        HugeConfig serverConfig = newConfig();
+        GraphManager manager = new GraphManager(serverConfig, new 
EventHub("test"));
+        HugeConfig graphConfig = newGraphConfig("rocksdb");
+
+        try {
+            Whitebox.invoke(manager.getClass(), "transferPdPeersConfig",
+                            manager, graphConfig);
+
+            
Assert.assertFalse(graphConfig.containsKey(CoreOptions.PD_PEERS.name()));
+        } finally {
+            manager.close();
+        }
+    }
+
+    @Test
+    public void testGraphManagerInjectsPdPeersForHStoreGraph() {
+        HugeConfig serverConfig = newConfig();
+        GraphManager manager = new GraphManager(serverConfig, new 
EventHub("test"));
+        HugeConfig graphConfig = newGraphConfig("hstore");
+        HugeConfig mixedCaseGraphConfig = newGraphConfig("HStore");
+
+        try {
+            Whitebox.invoke(manager.getClass(), "transferPdPeersConfig",
+                            manager, graphConfig);
+            Whitebox.invoke(manager.getClass(), "transferPdPeersConfig",
+                            manager, mixedCaseGraphConfig);
+
+            Assert.assertEquals(serverConfig.get(ServerOptions.PD_PEERS),
+                                graphConfig.get(CoreOptions.PD_PEERS));
+            Assert.assertEquals(serverConfig.get(ServerOptions.PD_PEERS),
+                                
mixedCaseGraphConfig.get(CoreOptions.PD_PEERS));
+        } finally {
+            manager.close();
+        }
+    }
+
+    private static HugeConfig newConfig() {
+        return new HugeConfig(new PropertiesConfiguration());
+    }
+
+    private static HugeConfig newGraphConfig(String backend) {
+        PropertiesConfiguration conf = new PropertiesConfiguration();
+        conf.setProperty(CoreOptions.BACKEND.name(), backend);
+        return new HugeConfig(conf);
+    }
+}
diff --git 
a/hugegraph-struct/src/main/java/org/apache/hugegraph/options/CoreOptions.java 
b/hugegraph-struct/src/main/java/org/apache/hugegraph/options/CoreOptions.java
index 849539419..caf0146bb 100644
--- 
a/hugegraph-struct/src/main/java/org/apache/hugegraph/options/CoreOptions.java
+++ 
b/hugegraph-struct/src/main/java/org/apache/hugegraph/options/CoreOptions.java
@@ -295,13 +295,7 @@ public class CoreOptions extends OptionHolder {
                     rangeInt(1, 500),
                     1
             );
-    public static final ConfigOption<String> SCHEDULER_TYPE =
-            new ConfigOption<>(
-                    "task.scheduler_type",
-                    "The type of scheduler used in distribution system.",
-                    allowValues("local", "distributed"),
-                    "local"
-            );
+
     public static final ConfigOption<Boolean> TASK_SYNC_DELETION =
             new ConfigOption<>(
                     "task.sync_deletion",

Reply via email to