You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@bigtop.apache.org by wu...@apache.org on 2024/08/05 06:37:10 UTC

(bigtop-manager) branch main updated: BIGTOP-4181: Refactor factory/runner for job/stage (#36)

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

wuzhiguo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/bigtop-manager.git


The following commit(s) were added to refs/heads/main by this push:
     new 4b3fa17  BIGTOP-4181: Refactor factory/runner for job/stage (#36)
4b3fa17 is described below

commit 4b3fa17630a481ee225b8cb68a0700c0a47e4078
Author: Zhiguo Wu <wu...@apache.org>
AuthorDate: Mon Aug 5 14:37:06 2024 +0800

    BIGTOP-4181: Refactor factory/runner for job/stage (#36)
---
 .../agent/executor/AbstractCommandExecutor.java    |   3 -
 ...or.java => CacheFileUpdateCommandExecutor.java} |   7 +-
 .../agent/executor/ComponentCommandExecutor.java   |   3 +-
 .../org/apache/bigtop/manager/dao/po/TaskPO.java   |  14 +-
 .../bigtop/manager/grpc/utils/ProtobufUtil.java    |   2 +-
 .../src/main/resources/proto/command.proto         |  13 +-
 .../factory/AbstractJobFactory.java}               |   8 +-
 .../command/{job => }/factory/JobFactories.java    |   2 +-
 .../command/{job => }/factory/JobFactory.java      |   7 +-
 .../factory/cluster/AbstractClusterJobFactory.java |   4 +-
 .../cluster/ClusterCreateJobFactory.java}          |  18 ++-
 .../component/AbstractComponentJobFactory.java     |   4 +-
 .../component/ComponentInstallJobFactory.java      |  11 +-
 .../component/ComponentRestartJobFactory.java      |  11 +-
 .../component/ComponentStartJobFactory.java        |  11 +-
 .../factory/component/ComponentStopJobFactory.java |  11 +-
 .../factory/host/AbstractHostJobFactory.java       |   4 +-
 .../host/HostAddJobFactory.java}                   |  18 ++-
 .../service/AbstractServiceJobFactory.java}        |   6 +-
 .../service/ServiceConfigureJobFactory.java        |  14 +-
 .../service/ServiceInstallJobFactory.java}         |  20 +--
 .../factory/service/ServiceRestartJobFactory.java  |  16 +-
 .../factory/service/ServiceStartJobFactory.java    |  14 +-
 .../factory/service/ServiceStopJobFactory.java     |  14 +-
 .../manager/server/command/job/AbstractJob.java    | 170 +++++++++++++++++++++
 ...viceJobFactory.java => AbstractServiceJob.java} |  60 ++++----
 ...rCreateJobRunner.java => ClusterCreateJob.java} |  69 ++++-----
 .../host/HostAddJobRunner.java => HostAddJob.java} |  48 +++---
 .../job/{factory/JobFactory.java => Job.java}      |  26 +++-
 .../command/job/{factory => }/JobContext.java      |   2 +-
 ...mandValidator.java => ServiceConfigureJob.java} |  20 ++-
 ...nstallJobRunner.java => ServiceInstallJob.java} | 108 ++++++++-----
 ...ommandValidator.java => ServiceRestartJob.java} |  20 ++-
 .../CommandValidator.java => ServiceStartJob.java} |  20 ++-
 .../CommandValidator.java => ServiceStopJob.java}  |  20 ++-
 .../command/job/factory/AbstractJobFactory.java    | 108 -------------
 .../factory/cluster/ClusterCreateJobFactory.java   |  51 -------
 .../job/factory/host/HostAddJobFactory.java        |  50 ------
 .../factory/service/ServiceInstallJobFactory.java  | 101 ------------
 .../command/job/runner/AbstractJobRunner.java      | 124 ---------------
 .../server/command/job/runner/JobRunner.java       |  71 ---------
 .../server/command/job/runner/JobRunners.java      |  89 -----------
 .../component/ComponentInstallJobRunner.java       |  40 -----
 .../component/ComponentRestartJobRunner.java       |  40 -----
 .../runner/component/ComponentStartJobRunner.java  |  40 -----
 .../runner/component/ComponentStopJobRunner.java   |  40 -----
 .../runner/service/ServiceConfigureJobRunner.java  |  40 -----
 .../runner/service/ServiceRestartJobRunner.java    |  40 -----
 .../job/runner/service/ServiceStartJobRunner.java  |  40 -----
 .../job/runner/service/ServiceStopJobRunner.java   |  40 -----
 .../command/scheduler/DefaultJobScheduler.java     |   9 +-
 .../server/command/scheduler/JobScheduler.java     |   6 +-
 .../command/stage/AbstractComponentStage.java      |  87 +++++++++++
 .../server/command/stage/AbstractStage.java        | 150 ++++++++++++++++++
 .../server/command/stage/CacheFileUpdateStage.java |  93 +++++++++++
 .../StageType.java => ComponentCheckStage.java}    |  29 ++--
 ...StageRunner.java => ComponentInstallStage.java} |  26 ++--
 .../StageType.java => ComponentStartStage.java}    |  29 ++--
 .../StageType.java => ComponentStopStage.java}     |  29 ++--
 .../server/command/stage/HostCheckStage.java       |  77 ++++++++++
 .../{factory/StageFactory.java => Stage.java}      |  43 +++---
 .../command/stage/{factory => }/StageContext.java  |   9 +-
 .../stage/factory/AbstractStageFactory.java        |  44 ------
 .../command/stage/factory/StageFactories.java      |  68 ---------
 .../component/ComponentInstallStageFactory.java    |  43 ------
 .../component/ComponentStartStageFactory.java      |  43 ------
 .../config/CacheDistributeStageFactory.java        |  83 ----------
 .../stage/factory/host/HostCheckStageFactory.java  | 100 ------------
 .../service/ServiceConfigureStageFactory.java      |  41 -----
 .../command/stage/runner/AbstractStageRunner.java  | 151 ------------------
 .../server/command/stage/runner/StageRunner.java   |  93 -----------
 .../server/command/stage/runner/StageRunners.java  |  79 ----------
 .../component/ComponentCheckStageRunner.java       |  38 -----
 .../service/ServiceConfigureStageRunner.java       |  38 -----
 .../AbstractComponentTask.java}                    |  99 ++++--------
 .../manager/server/command/task/AbstractTask.java  | 140 +++++++++++++++++
 .../CacheFileUpdateTask.java}                      | 118 +++++++-------
 .../ComponentCheckTask.java}                       |  23 ++-
 .../ComponentInstallTask.java}                     |  43 +++---
 .../ComponentStartTask.java}                       |  42 ++---
 .../ComponentStopTask.java}                        |  43 +++---
 .../manager/server/command/task/HostCheckTask.java |  61 ++++++++
 .../factory/StageType.java => task/Task.java}      |  24 +--
 .../TaskContext.java}                              |  49 +++---
 .../validator/ClusterCreateValidator.java          |   2 +-
 .../{job => }/validator/ClusterHostValidator.java  |   2 +-
 .../{job => }/validator/CommandValidator.java      |   2 +-
 .../{job => }/validator/HostAddValidator.java      |   2 +-
 .../validator/RequiredServicesValidator.java       |   2 +-
 .../{job => }/validator/ServiceHostValidator.java  |   2 +-
 .../{job => }/validator/StackValidator.java        |   2 +-
 .../{job => }/validator/ValidatorContext.java      |   2 +-
 .../validator/ValidatorExecutionChain.java         |   2 +-
 .../manager/server/holder/SpringContextHolder.java |  23 +--
 .../server/model/converter/ClusterConverter.java   |   2 +
 .../model/dto/command/ServiceCommandDTO.java       |   2 +
 .../model/req/command/ServiceCommandReq.java       |   3 +
 .../server/scheduler/ComponentStatusScheduler.java |   3 +-
 .../server/service/impl/ClusterServiceImpl.java    |   4 +-
 .../server/service/impl/CommandServiceImpl.java    |  76 ++++++++-
 .../server/service/impl/ConfigServiceImpl.java     |   3 +-
 .../server/service/impl/JobServiceImpl.java        |  71 ++++++++-
 .../server/service/impl/ServiceServiceImpl.java    |   4 +-
 .../src/main/resources/ddl/MySQL-DDL-CREATE.sql    |   4 +-
 .../manager/stack/core/executor/StackExecutor.java |   2 +-
 .../src/components/service-add/choose-services.vue |   3 +-
 .../src/components/service-add/index.vue           |   1 +
 107 files changed, 1606 insertions(+), 2375 deletions(-)

diff --git a/bigtop-manager-agent/src/main/java/org/apache/bigtop/manager/agent/executor/AbstractCommandExecutor.java b/bigtop-manager-agent/src/main/java/org/apache/bigtop/manager/agent/executor/AbstractCommandExecutor.java
index ccbd2a9..a295d21 100644
--- a/bigtop-manager-agent/src/main/java/org/apache/bigtop/manager/agent/executor/AbstractCommandExecutor.java
+++ b/bigtop-manager-agent/src/main/java/org/apache/bigtop/manager/agent/executor/AbstractCommandExecutor.java
@@ -52,11 +52,8 @@ public abstract class AbstractCommandExecutor implements CommandExecutor {
             log.error("Run command failed, {}", request, e);
         }
 
-        commandReplyBuilder.setType(request.getType());
         commandReplyBuilder.setHostname(request.getHostname());
         commandReplyBuilder.setTaskId(request.getTaskId());
-        commandReplyBuilder.setStageId(request.getStageId());
-        commandReplyBuilder.setJobId(request.getJobId());
         return commandReplyBuilder.build();
     }
 
diff --git a/bigtop-manager-agent/src/main/java/org/apache/bigtop/manager/agent/executor/CacheDistributeCommandExecutor.java b/bigtop-manager-agent/src/main/java/org/apache/bigtop/manager/agent/executor/CacheFileUpdateCommandExecutor.java
similarity index 95%
rename from bigtop-manager-agent/src/main/java/org/apache/bigtop/manager/agent/executor/CacheDistributeCommandExecutor.java
rename to bigtop-manager-agent/src/main/java/org/apache/bigtop/manager/agent/executor/CacheFileUpdateCommandExecutor.java
index 0098fdd..13fbed7 100644
--- a/bigtop-manager-agent/src/main/java/org/apache/bigtop/manager/agent/executor/CacheDistributeCommandExecutor.java
+++ b/bigtop-manager-agent/src/main/java/org/apache/bigtop/manager/agent/executor/CacheFileUpdateCommandExecutor.java
@@ -27,6 +27,7 @@ import org.apache.bigtop.manager.stack.common.utils.linux.LinuxFileUtils;
 
 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
 import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
 
 import lombok.extern.slf4j.Slf4j;
 
@@ -41,13 +42,13 @@ import static org.apache.bigtop.manager.common.constants.CacheFiles.SETTINGS_INF
 import static org.apache.bigtop.manager.common.constants.CacheFiles.USERS_INFO;
 
 @Slf4j
-@org.springframework.stereotype.Component
+@Component
 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class CacheDistributeCommandExecutor extends AbstractCommandExecutor {
+public class CacheFileUpdateCommandExecutor extends AbstractCommandExecutor {
 
     @Override
     public CommandType getCommandType() {
-        return CommandType.CACHE_DISTRIBUTE;
+        return CommandType.UPDATE_CACHE_FILES;
     }
 
     @Override
diff --git a/bigtop-manager-agent/src/main/java/org/apache/bigtop/manager/agent/executor/ComponentCommandExecutor.java b/bigtop-manager-agent/src/main/java/org/apache/bigtop/manager/agent/executor/ComponentCommandExecutor.java
index 7df2bd3..ccc46b6 100644
--- a/bigtop-manager-agent/src/main/java/org/apache/bigtop/manager/agent/executor/ComponentCommandExecutor.java
+++ b/bigtop-manager-agent/src/main/java/org/apache/bigtop/manager/agent/executor/ComponentCommandExecutor.java
@@ -26,11 +26,12 @@ import org.apache.bigtop.manager.stack.core.executor.StackExecutor;
 
 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
 import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
 
 import lombok.extern.slf4j.Slf4j;
 
 @Slf4j
-@org.springframework.stereotype.Component
+@Component
 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
 public class ComponentCommandExecutor extends AbstractCommandExecutor {
 
diff --git a/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/po/TaskPO.java b/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/po/TaskPO.java
index 26f44e7..a6fc092 100644
--- a/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/po/TaskPO.java
+++ b/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/po/TaskPO.java
@@ -61,8 +61,10 @@ public class TaskPO extends BasePO {
     @Column(name = "name")
     private String name;
 
-    @Column(name = "message_id")
-    private String messageId;
+    @Lob
+    @Basic(fetch = FetchType.LAZY)
+    @Column(name = "context", length = 16777216)
+    private String context;
 
     @Column(name = "state")
     private JobState state;
@@ -79,14 +81,6 @@ public class TaskPO extends BasePO {
     @Column(name = "custom_command")
     private String customCommand;
 
-    @Lob
-    @Basic(fetch = FetchType.LAZY)
-    @Column(name = "custom_commands", length = 16777216)
-    private String customCommands;
-
-    @Column(name = "command_script")
-    private String commandScript;
-
     @Column(name = "hostname")
     private String hostname;
 
diff --git a/bigtop-manager-grpc/src/main/java/org/apache/bigtop/manager/grpc/utils/ProtobufUtil.java b/bigtop-manager-grpc/src/main/java/org/apache/bigtop/manager/grpc/utils/ProtobufUtil.java
index dc212e9..6ee9450 100644
--- a/bigtop-manager-grpc/src/main/java/org/apache/bigtop/manager/grpc/utils/ProtobufUtil.java
+++ b/bigtop-manager-grpc/src/main/java/org/apache/bigtop/manager/grpc/utils/ProtobufUtil.java
@@ -38,7 +38,7 @@ public class ProtobufUtil {
 
     public static <T extends Message> String toJson(T message) {
         try {
-            return JsonFormat.printer().print(message);
+            return JsonFormat.printer().omittingInsignificantWhitespace().print(message);
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
diff --git a/bigtop-manager-grpc/src/main/resources/proto/command.proto b/bigtop-manager-grpc/src/main/resources/proto/command.proto
index e2c09a4..e008c6b 100644
--- a/bigtop-manager-grpc/src/main/resources/proto/command.proto
+++ b/bigtop-manager-grpc/src/main/resources/proto/command.proto
@@ -29,24 +29,19 @@ service CommandService {
 enum CommandType {
   COMPONENT = 0;
   HOST_CHECK = 1;
-  CACHE_DISTRIBUTE = 2;
+  UPDATE_CACHE_FILES = 2;
 }
 
 message CommandRequest {
   string payload = 1;
   string hostname = 2;
-  int64 job_id = 3;
-  int64 stage_id = 4;
-  int64 task_id = 5;
-  CommandType type = 6;
+  int64 task_id = 3;
+  CommandType type = 4;
 }
 
 message CommandReply {
   int32 code = 1;
   string result = 2;
   string hostname = 3;
-  int64 job_id = 4;
-  int64 stage_id = 5;
-  int64 task_id = 6;
-  CommandType type = 7;
+  int64 task_id = 4;
 }
\ No newline at end of file
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/enums/JobStrategyType.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/AbstractJobFactory.java
similarity index 86%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/enums/JobStrategyType.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/AbstractJobFactory.java
index 8c586d2..c5cbdf5 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/enums/JobStrategyType.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/AbstractJobFactory.java
@@ -16,10 +16,6 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.enums;
+package org.apache.bigtop.manager.server.command.factory;
 
-public enum JobStrategyType {
-    OVER_ON_FAIL,
-
-    CONTINUE_ON_FAIL,
-}
+public abstract class AbstractJobFactory implements JobFactory {}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/JobFactories.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/JobFactories.java
similarity index 97%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/JobFactories.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/JobFactories.java
index 9fb1230..7e01308 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/JobFactories.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/JobFactories.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.factory;
+package org.apache.bigtop.manager.server.command.factory;
 
 import org.apache.bigtop.manager.server.command.CommandIdentifier;
 import org.apache.bigtop.manager.server.enums.ApiExceptionEnum;
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/JobFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/JobFactory.java
similarity index 81%
copy from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/JobFactory.java
copy to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/JobFactory.java
index 89e3953..4d2e0c4 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/JobFactory.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/JobFactory.java
@@ -16,14 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.factory;
+package org.apache.bigtop.manager.server.command.factory;
 
-import org.apache.bigtop.manager.dao.po.JobPO;
 import org.apache.bigtop.manager.server.command.CommandIdentifier;
+import org.apache.bigtop.manager.server.command.job.Job;
+import org.apache.bigtop.manager.server.command.job.JobContext;
 
 public interface JobFactory {
 
     CommandIdentifier getCommandIdentifier();
 
-    JobPO createJob(JobContext jobContext);
+    Job createJob(JobContext jobContext);
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/cluster/AbstractClusterJobFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/cluster/AbstractClusterJobFactory.java
similarity index 85%
copy from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/cluster/AbstractClusterJobFactory.java
copy to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/cluster/AbstractClusterJobFactory.java
index da8709c..20c2659 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/cluster/AbstractClusterJobFactory.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/cluster/AbstractClusterJobFactory.java
@@ -16,8 +16,8 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.factory.cluster;
+package org.apache.bigtop.manager.server.command.factory.cluster;
 
-import org.apache.bigtop.manager.server.command.job.factory.AbstractJobFactory;
+import org.apache.bigtop.manager.server.command.factory.AbstractJobFactory;
 
 public abstract class AbstractClusterJobFactory extends AbstractJobFactory {}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/service/ServiceConfigureJobFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/cluster/ClusterCreateJobFactory.java
similarity index 69%
copy from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/service/ServiceConfigureJobFactory.java
copy to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/cluster/ClusterCreateJobFactory.java
index c07382c..ef9f5ad 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/service/ServiceConfigureJobFactory.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/cluster/ClusterCreateJobFactory.java
@@ -16,31 +16,33 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.factory.service;
+package org.apache.bigtop.manager.server.command.factory.cluster;
 
 import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.server.command.CommandIdentifier;
+import org.apache.bigtop.manager.server.command.job.ClusterCreateJob;
+import org.apache.bigtop.manager.server.command.job.Job;
+import org.apache.bigtop.manager.server.command.job.JobContext;
 import org.apache.bigtop.manager.server.enums.CommandLevel;
 
 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
 import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
 
 import lombok.extern.slf4j.Slf4j;
 
 @Slf4j
-@org.springframework.stereotype.Component
+@Component
 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class ServiceConfigureJobFactory extends AbstractServiceJobFactory {
+public class ClusterCreateJobFactory extends AbstractClusterJobFactory {
 
     @Override
     public CommandIdentifier getCommandIdentifier() {
-        return new CommandIdentifier(CommandLevel.SERVICE, Command.CONFIGURE);
+        return new CommandIdentifier(CommandLevel.CLUSTER, Command.CREATE);
     }
 
     @Override
-    public void createStagesAndTasks() {
-        super.initAttrs();
-
-        super.createCacheStage();
+    public Job createJob(JobContext jobContext) {
+        return new ClusterCreateJob(jobContext);
     }
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/component/AbstractComponentJobFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/component/AbstractComponentJobFactory.java
similarity index 85%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/component/AbstractComponentJobFactory.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/component/AbstractComponentJobFactory.java
index 6666ecf..b82bbf4 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/component/AbstractComponentJobFactory.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/component/AbstractComponentJobFactory.java
@@ -16,8 +16,8 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.factory.component;
+package org.apache.bigtop.manager.server.command.factory.component;
 
-import org.apache.bigtop.manager.server.command.job.factory.AbstractJobFactory;
+import org.apache.bigtop.manager.server.command.factory.AbstractJobFactory;
 
 public abstract class AbstractComponentJobFactory extends AbstractJobFactory {}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/component/ComponentInstallJobFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/component/ComponentInstallJobFactory.java
similarity index 81%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/component/ComponentInstallJobFactory.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/component/ComponentInstallJobFactory.java
index d1ad8be..74308ec 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/component/ComponentInstallJobFactory.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/component/ComponentInstallJobFactory.java
@@ -16,19 +16,22 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.factory.component;
+package org.apache.bigtop.manager.server.command.factory.component;
 
 import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.server.command.CommandIdentifier;
+import org.apache.bigtop.manager.server.command.job.Job;
+import org.apache.bigtop.manager.server.command.job.JobContext;
 import org.apache.bigtop.manager.server.enums.CommandLevel;
 
 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
 import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
 
 import lombok.extern.slf4j.Slf4j;
 
 @Slf4j
-@org.springframework.stereotype.Component
+@Component
 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
 public class ComponentInstallJobFactory extends AbstractComponentJobFactory {
 
@@ -38,5 +41,7 @@ public class ComponentInstallJobFactory extends AbstractComponentJobFactory {
     }
 
     @Override
-    public void createStagesAndTasks() {}
+    public Job createJob(JobContext jobContext) {
+        return null;
+    }
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/component/ComponentRestartJobFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/component/ComponentRestartJobFactory.java
similarity index 81%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/component/ComponentRestartJobFactory.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/component/ComponentRestartJobFactory.java
index f6352b2..5c9c8f8 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/component/ComponentRestartJobFactory.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/component/ComponentRestartJobFactory.java
@@ -16,19 +16,22 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.factory.component;
+package org.apache.bigtop.manager.server.command.factory.component;
 
 import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.server.command.CommandIdentifier;
+import org.apache.bigtop.manager.server.command.job.Job;
+import org.apache.bigtop.manager.server.command.job.JobContext;
 import org.apache.bigtop.manager.server.enums.CommandLevel;
 
 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
 import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
 
 import lombok.extern.slf4j.Slf4j;
 
 @Slf4j
-@org.springframework.stereotype.Component
+@Component
 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
 public class ComponentRestartJobFactory extends AbstractComponentJobFactory {
 
@@ -38,5 +41,7 @@ public class ComponentRestartJobFactory extends AbstractComponentJobFactory {
     }
 
     @Override
-    public void createStagesAndTasks() {}
+    public Job createJob(JobContext jobContext) {
+        return null;
+    }
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/component/ComponentStartJobFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/component/ComponentStartJobFactory.java
similarity index 81%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/component/ComponentStartJobFactory.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/component/ComponentStartJobFactory.java
index 16ac6bf..eb16c17 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/component/ComponentStartJobFactory.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/component/ComponentStartJobFactory.java
@@ -16,19 +16,22 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.factory.component;
+package org.apache.bigtop.manager.server.command.factory.component;
 
 import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.server.command.CommandIdentifier;
+import org.apache.bigtop.manager.server.command.job.Job;
+import org.apache.bigtop.manager.server.command.job.JobContext;
 import org.apache.bigtop.manager.server.enums.CommandLevel;
 
 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
 import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
 
 import lombok.extern.slf4j.Slf4j;
 
 @Slf4j
-@org.springframework.stereotype.Component
+@Component
 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
 public class ComponentStartJobFactory extends AbstractComponentJobFactory {
 
@@ -38,5 +41,7 @@ public class ComponentStartJobFactory extends AbstractComponentJobFactory {
     }
 
     @Override
-    public void createStagesAndTasks() {}
+    public Job createJob(JobContext jobContext) {
+        return null;
+    }
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/component/ComponentStopJobFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/component/ComponentStopJobFactory.java
similarity index 81%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/component/ComponentStopJobFactory.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/component/ComponentStopJobFactory.java
index 739a9e0..8f2a145 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/component/ComponentStopJobFactory.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/component/ComponentStopJobFactory.java
@@ -16,19 +16,22 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.factory.component;
+package org.apache.bigtop.manager.server.command.factory.component;
 
 import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.server.command.CommandIdentifier;
+import org.apache.bigtop.manager.server.command.job.Job;
+import org.apache.bigtop.manager.server.command.job.JobContext;
 import org.apache.bigtop.manager.server.enums.CommandLevel;
 
 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
 import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
 
 import lombok.extern.slf4j.Slf4j;
 
 @Slf4j
-@org.springframework.stereotype.Component
+@Component
 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
 public class ComponentStopJobFactory extends AbstractComponentJobFactory {
 
@@ -38,5 +41,7 @@ public class ComponentStopJobFactory extends AbstractComponentJobFactory {
     }
 
     @Override
-    public void createStagesAndTasks() {}
+    public Job createJob(JobContext jobContext) {
+        return null;
+    }
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/host/AbstractHostJobFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/host/AbstractHostJobFactory.java
similarity index 85%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/host/AbstractHostJobFactory.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/host/AbstractHostJobFactory.java
index 4b2e2d0..f8ba730 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/host/AbstractHostJobFactory.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/host/AbstractHostJobFactory.java
@@ -16,8 +16,8 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.factory.host;
+package org.apache.bigtop.manager.server.command.factory.host;
 
-import org.apache.bigtop.manager.server.command.job.factory.AbstractJobFactory;
+import org.apache.bigtop.manager.server.command.factory.AbstractJobFactory;
 
 public abstract class AbstractHostJobFactory extends AbstractJobFactory {}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/service/ServiceConfigureJobFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/host/HostAddJobFactory.java
similarity index 70%
copy from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/service/ServiceConfigureJobFactory.java
copy to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/host/HostAddJobFactory.java
index c07382c..fe7a06c 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/service/ServiceConfigureJobFactory.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/host/HostAddJobFactory.java
@@ -16,31 +16,33 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.factory.service;
+package org.apache.bigtop.manager.server.command.factory.host;
 
 import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.server.command.CommandIdentifier;
+import org.apache.bigtop.manager.server.command.job.HostAddJob;
+import org.apache.bigtop.manager.server.command.job.Job;
+import org.apache.bigtop.manager.server.command.job.JobContext;
 import org.apache.bigtop.manager.server.enums.CommandLevel;
 
 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
 import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
 
 import lombok.extern.slf4j.Slf4j;
 
 @Slf4j
-@org.springframework.stereotype.Component
+@Component
 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class ServiceConfigureJobFactory extends AbstractServiceJobFactory {
+public class HostAddJobFactory extends AbstractHostJobFactory {
 
     @Override
     public CommandIdentifier getCommandIdentifier() {
-        return new CommandIdentifier(CommandLevel.SERVICE, Command.CONFIGURE);
+        return new CommandIdentifier(CommandLevel.HOST, Command.INSTALL);
     }
 
     @Override
-    public void createStagesAndTasks() {
-        super.initAttrs();
-
-        super.createCacheStage();
+    public Job createJob(JobContext jobContext) {
+        return new HostAddJob(jobContext);
     }
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/cluster/AbstractClusterJobFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/service/AbstractServiceJobFactory.java
similarity index 79%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/cluster/AbstractClusterJobFactory.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/service/AbstractServiceJobFactory.java
index da8709c..77d6037 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/cluster/AbstractClusterJobFactory.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/service/AbstractServiceJobFactory.java
@@ -16,8 +16,8 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.factory.cluster;
+package org.apache.bigtop.manager.server.command.factory.service;
 
-import org.apache.bigtop.manager.server.command.job.factory.AbstractJobFactory;
+import org.apache.bigtop.manager.server.command.factory.AbstractJobFactory;
 
-public abstract class AbstractClusterJobFactory extends AbstractJobFactory {}
+public abstract class AbstractServiceJobFactory extends AbstractJobFactory {}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/service/ServiceConfigureJobFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/service/ServiceConfigureJobFactory.java
similarity index 77%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/service/ServiceConfigureJobFactory.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/service/ServiceConfigureJobFactory.java
index c07382c..15c804d 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/service/ServiceConfigureJobFactory.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/service/ServiceConfigureJobFactory.java
@@ -16,19 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.factory.service;
+package org.apache.bigtop.manager.server.command.factory.service;
 
 import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.server.command.CommandIdentifier;
+import org.apache.bigtop.manager.server.command.job.Job;
+import org.apache.bigtop.manager.server.command.job.JobContext;
+import org.apache.bigtop.manager.server.command.job.ServiceConfigureJob;
 import org.apache.bigtop.manager.server.enums.CommandLevel;
 
 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
 import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
 
 import lombok.extern.slf4j.Slf4j;
 
 @Slf4j
-@org.springframework.stereotype.Component
+@Component
 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
 public class ServiceConfigureJobFactory extends AbstractServiceJobFactory {
 
@@ -38,9 +42,7 @@ public class ServiceConfigureJobFactory extends AbstractServiceJobFactory {
     }
 
     @Override
-    public void createStagesAndTasks() {
-        super.initAttrs();
-
-        super.createCacheStage();
+    public Job createJob(JobContext jobContext) {
+        return new ServiceConfigureJob(jobContext);
     }
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/service/ServiceRestartJobFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/service/ServiceInstallJobFactory.java
similarity index 73%
copy from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/service/ServiceRestartJobFactory.java
copy to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/service/ServiceInstallJobFactory.java
index 9586144..4b0f9d7 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/service/ServiceRestartJobFactory.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/service/ServiceInstallJobFactory.java
@@ -16,33 +16,33 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.factory.service;
+package org.apache.bigtop.manager.server.command.factory.service;
 
 import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.server.command.CommandIdentifier;
+import org.apache.bigtop.manager.server.command.job.Job;
+import org.apache.bigtop.manager.server.command.job.JobContext;
+import org.apache.bigtop.manager.server.command.job.ServiceInstallJob;
 import org.apache.bigtop.manager.server.enums.CommandLevel;
 
 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
 import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
 
 import lombok.extern.slf4j.Slf4j;
 
 @Slf4j
-@org.springframework.stereotype.Component
+@Component
 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class ServiceRestartJobFactory extends AbstractServiceJobFactory {
+public class ServiceInstallJobFactory extends AbstractServiceJobFactory {
 
     @Override
     public CommandIdentifier getCommandIdentifier() {
-        return new CommandIdentifier(CommandLevel.SERVICE, Command.RESTART);
+        return new CommandIdentifier(CommandLevel.SERVICE, Command.INSTALL);
     }
 
     @Override
-    protected void createStagesAndTasks() {
-        super.initAttrs();
-
-        super.createStopStages();
-
-        super.createStartStages();
+    public Job createJob(JobContext jobContext) {
+        return new ServiceInstallJob(jobContext);
     }
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/service/ServiceRestartJobFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/service/ServiceRestartJobFactory.java
similarity index 77%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/service/ServiceRestartJobFactory.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/service/ServiceRestartJobFactory.java
index 9586144..f71c9d0 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/service/ServiceRestartJobFactory.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/service/ServiceRestartJobFactory.java
@@ -16,19 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.factory.service;
+package org.apache.bigtop.manager.server.command.factory.service;
 
 import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.server.command.CommandIdentifier;
+import org.apache.bigtop.manager.server.command.job.Job;
+import org.apache.bigtop.manager.server.command.job.JobContext;
+import org.apache.bigtop.manager.server.command.job.ServiceRestartJob;
 import org.apache.bigtop.manager.server.enums.CommandLevel;
 
 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
 import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
 
 import lombok.extern.slf4j.Slf4j;
 
 @Slf4j
-@org.springframework.stereotype.Component
+@Component
 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
 public class ServiceRestartJobFactory extends AbstractServiceJobFactory {
 
@@ -38,11 +42,7 @@ public class ServiceRestartJobFactory extends AbstractServiceJobFactory {
     }
 
     @Override
-    protected void createStagesAndTasks() {
-        super.initAttrs();
-
-        super.createStopStages();
-
-        super.createStartStages();
+    public Job createJob(JobContext jobContext) {
+        return new ServiceRestartJob(jobContext);
     }
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/service/ServiceStartJobFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/service/ServiceStartJobFactory.java
similarity index 77%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/service/ServiceStartJobFactory.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/service/ServiceStartJobFactory.java
index 961bccf..d84995f 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/service/ServiceStartJobFactory.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/service/ServiceStartJobFactory.java
@@ -16,19 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.factory.service;
+package org.apache.bigtop.manager.server.command.factory.service;
 
 import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.server.command.CommandIdentifier;
+import org.apache.bigtop.manager.server.command.job.Job;
+import org.apache.bigtop.manager.server.command.job.JobContext;
+import org.apache.bigtop.manager.server.command.job.ServiceStartJob;
 import org.apache.bigtop.manager.server.enums.CommandLevel;
 
 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
 import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
 
 import lombok.extern.slf4j.Slf4j;
 
 @Slf4j
-@org.springframework.stereotype.Component
+@Component
 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
 public class ServiceStartJobFactory extends AbstractServiceJobFactory {
 
@@ -38,9 +42,7 @@ public class ServiceStartJobFactory extends AbstractServiceJobFactory {
     }
 
     @Override
-    protected void createStagesAndTasks() {
-        super.initAttrs();
-
-        super.createStartStages();
+    public Job createJob(JobContext jobContext) {
+        return new ServiceStartJob(jobContext);
     }
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/service/ServiceStopJobFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/service/ServiceStopJobFactory.java
similarity index 77%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/service/ServiceStopJobFactory.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/service/ServiceStopJobFactory.java
index c6605c2..b2e2504 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/service/ServiceStopJobFactory.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/service/ServiceStopJobFactory.java
@@ -16,19 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.factory.service;
+package org.apache.bigtop.manager.server.command.factory.service;
 
 import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.server.command.CommandIdentifier;
+import org.apache.bigtop.manager.server.command.job.Job;
+import org.apache.bigtop.manager.server.command.job.JobContext;
+import org.apache.bigtop.manager.server.command.job.ServiceStopJob;
 import org.apache.bigtop.manager.server.enums.CommandLevel;
 
 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
 import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
 
 import lombok.extern.slf4j.Slf4j;
 
 @Slf4j
-@org.springframework.stereotype.Component
+@Component
 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
 public class ServiceStopJobFactory extends AbstractServiceJobFactory {
 
@@ -38,9 +42,7 @@ public class ServiceStopJobFactory extends AbstractServiceJobFactory {
     }
 
     @Override
-    protected void createStagesAndTasks() {
-        super.initAttrs();
-
-        super.createStopStages();
+    public Job createJob(JobContext jobContext) {
+        return new ServiceStopJob(jobContext);
     }
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/AbstractJob.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/AbstractJob.java
new file mode 100644
index 0000000..8987db0
--- /dev/null
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/AbstractJob.java
@@ -0,0 +1,170 @@
+/*
+ * 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
+ *
+ *    https://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.bigtop.manager.server.command.job;
+
+import org.apache.bigtop.manager.common.enums.JobState;
+import org.apache.bigtop.manager.common.utils.JsonUtils;
+import org.apache.bigtop.manager.dao.po.ClusterPO;
+import org.apache.bigtop.manager.dao.po.JobPO;
+import org.apache.bigtop.manager.dao.po.StagePO;
+import org.apache.bigtop.manager.dao.po.TaskPO;
+import org.apache.bigtop.manager.dao.repository.ClusterRepository;
+import org.apache.bigtop.manager.dao.repository.JobRepository;
+import org.apache.bigtop.manager.dao.repository.StageRepository;
+import org.apache.bigtop.manager.dao.repository.TaskRepository;
+import org.apache.bigtop.manager.server.command.stage.Stage;
+import org.apache.bigtop.manager.server.command.task.Task;
+import org.apache.bigtop.manager.server.holder.SpringContextHolder;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public abstract class AbstractJob implements Job {
+
+    protected ClusterRepository clusterRepository;
+    protected JobRepository jobRepository;
+    protected StageRepository stageRepository;
+    protected TaskRepository taskRepository;
+
+    protected JobContext jobContext;
+    protected List<Stage> stages;
+
+    protected ClusterPO clusterPO;
+
+    /**
+     * Do not use this directly, please use {@link #getJobPO()} to make sure it's initialized.
+     */
+    private JobPO jobPO;
+
+    public AbstractJob(JobContext jobContext) {
+        this.jobContext = jobContext;
+        this.stages = new ArrayList<>();
+
+        injectBeans();
+
+        beforeCreateStages();
+
+        createStages();
+    }
+
+    protected void injectBeans() {
+        this.clusterRepository = SpringContextHolder.getBean(ClusterRepository.class);
+        this.jobRepository = SpringContextHolder.getBean(JobRepository.class);
+        this.stageRepository = SpringContextHolder.getBean(StageRepository.class);
+        this.taskRepository = SpringContextHolder.getBean(TaskRepository.class);
+    }
+
+    protected void beforeCreateStages() {
+        Long clusterId = jobContext.getCommandDTO().getClusterId();
+        this.clusterPO = clusterId == null ? new ClusterPO() : clusterRepository.getReferenceById(clusterId);
+    }
+
+    protected abstract void createStages();
+
+    @Override
+    public void beforeRun() {
+        JobPO jobPO = getJobPO();
+        jobPO.setState(JobState.PROCESSING);
+        jobRepository.save(jobPO);
+    }
+
+    @Override
+    public void run() {
+        beforeRun();
+
+        boolean success = true;
+        LinkedBlockingQueue<Stage> queue = new LinkedBlockingQueue<>(stages);
+        while (!queue.isEmpty()) {
+            Stage stage = queue.poll();
+            Boolean stageSuccess = stage.run();
+
+            if (!stageSuccess) {
+                success = false;
+                break;
+            }
+        }
+
+        if (success) {
+            onSuccess();
+        } else {
+            onFailure();
+        }
+    }
+
+    @Override
+    public void onSuccess() {
+        JobPO jobPO = getJobPO();
+        jobPO.setState(JobState.SUCCESSFUL);
+        jobRepository.save(jobPO);
+    }
+
+    @Override
+    public void onFailure() {
+        JobPO jobPO = getJobPO();
+        List<StagePO> stagePOList = new ArrayList<>();
+        List<TaskPO> taskPOList = new ArrayList<>();
+
+        jobPO.setState(JobState.FAILED);
+
+        for (Stage stage : getStages()) {
+            StagePO stagePO = stage.getStagePO();
+            if (stagePO.getState() == JobState.PENDING) {
+                stagePO.setState(JobState.CANCELED);
+                stagePOList.add(stagePO);
+
+                for (Task task : stage.getTasks()) {
+                    TaskPO taskPO = task.getTaskPO();
+                    taskPO.setState(JobState.CANCELED);
+                    taskPOList.add(taskPO);
+                }
+            }
+        }
+
+        taskRepository.saveAll(taskPOList);
+        stageRepository.saveAll(stagePOList);
+        jobRepository.save(jobPO);
+    }
+
+    @Override
+    public JobContext getJobContext() {
+        return jobContext;
+    }
+
+    @Override
+    public List<Stage> getStages() {
+        return stages;
+    }
+
+    @Override
+    public void loadJobPO(JobPO jobPO) {
+        this.jobPO = jobPO;
+    }
+
+    @Override
+    public JobPO getJobPO() {
+        if (jobPO == null) {
+            jobPO = new JobPO();
+            jobPO.setName(getName());
+            jobPO.setContext(JsonUtils.writeAsString(jobContext));
+        }
+
+        return jobPO;
+    }
+}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/service/AbstractServiceJobFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/AbstractServiceJob.java
similarity index 85%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/service/AbstractServiceJobFactory.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/AbstractServiceJob.java
index 666c3b5..1315077 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/service/AbstractServiceJobFactory.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/AbstractServiceJob.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.factory.service;
+package org.apache.bigtop.manager.server.command.job;
 
 import org.apache.bigtop.manager.common.constants.ComponentCategories;
 import org.apache.bigtop.manager.common.enums.Command;
@@ -26,11 +26,14 @@ import org.apache.bigtop.manager.dao.po.HostComponentPO;
 import org.apache.bigtop.manager.dao.po.HostPO;
 import org.apache.bigtop.manager.dao.repository.ComponentRepository;
 import org.apache.bigtop.manager.dao.repository.HostComponentRepository;
-import org.apache.bigtop.manager.server.command.job.factory.AbstractJobFactory;
-import org.apache.bigtop.manager.server.command.stage.factory.StageContext;
-import org.apache.bigtop.manager.server.command.stage.factory.StageFactories;
-import org.apache.bigtop.manager.server.command.stage.factory.StageType;
+import org.apache.bigtop.manager.server.command.stage.CacheFileUpdateStage;
+import org.apache.bigtop.manager.server.command.stage.ComponentCheckStage;
+import org.apache.bigtop.manager.server.command.stage.ComponentInstallStage;
+import org.apache.bigtop.manager.server.command.stage.ComponentStartStage;
+import org.apache.bigtop.manager.server.command.stage.ComponentStopStage;
+import org.apache.bigtop.manager.server.command.stage.StageContext;
 import org.apache.bigtop.manager.server.exception.ServerException;
+import org.apache.bigtop.manager.server.holder.SpringContextHolder;
 import org.apache.bigtop.manager.server.model.dto.ComponentDTO;
 import org.apache.bigtop.manager.server.model.dto.ServiceDTO;
 import org.apache.bigtop.manager.server.model.dto.command.ServiceCommandDTO;
@@ -41,39 +44,45 @@ import org.apache.bigtop.manager.server.utils.StackUtils;
 
 import org.apache.commons.collections4.CollectionUtils;
 
-import jakarta.annotation.Resource;
 import java.util.ArrayList;
 import java.util.List;
 
-/**
- * A Service Job can be seen as a collection of multiple Components and Hosts,
- * so it can directly inherit from AbstractComponentJobFactory.
- */
-public abstract class AbstractServiceJobFactory extends AbstractJobFactory {
+public abstract class AbstractServiceJob extends AbstractJob {
 
-    @Resource
     protected ComponentRepository componentRepository;
-
-    @Resource
     protected HostComponentRepository hostComponentRepository;
 
     protected String stackName;
-
     protected String stackVersion;
-
     protected DAG<String, ComponentCommandWrapper, DagGraphEdge> dag;
 
-    protected void initAttrs() {
+    public AbstractServiceJob(JobContext jobContext) {
+        super(jobContext);
+    }
+
+    @Override
+    protected void injectBeans() {
+        super.injectBeans();
+
+        this.componentRepository = SpringContextHolder.getBean(ComponentRepository.class);
+        this.hostComponentRepository = SpringContextHolder.getBean(HostComponentRepository.class);
+    }
+
+    @Override
+    protected void beforeCreateStages() {
+        super.beforeCreateStages();
+
         stackName = clusterPO.getStackPO().getStackName();
         stackVersion = clusterPO.getStackPO().getStackVersion();
         dag = StackUtils.getStackDagMap().get(StackUtils.fullStackName(stackName, stackVersion));
     }
 
     protected StageContext createStageContext(String serviceName, String componentName, List<String> hostnames) {
+        StageContext stageContext = StageContext.fromCommandDTO(jobContext.getCommandDTO());
+
         ServiceDTO serviceDTO = StackUtils.getServiceDTO(stackName, stackVersion, serviceName);
         ComponentDTO componentDTO = StackUtils.getComponentDTO(stackName, stackVersion, componentName);
 
-        StageContext stageContext = StageContext.fromPayload(JsonUtils.writeAsString(jobContext.getCommandDTO()));
         stageContext.setServiceDTO(serviceDTO);
         stageContext.setComponentDTO(componentDTO);
         stageContext.setStackName(stackName);
@@ -149,8 +158,7 @@ public abstract class AbstractServiceJobFactory extends AbstractJobFactory {
         StageContext stageContext = StageContext.fromPayload(JsonUtils.writeAsString(jobContext.getCommandDTO()));
         stageContext.setStackName(stackName);
         stageContext.setStackVersion(stackVersion);
-        stagePOList.add(
-                StageFactories.getStageFactory(StageType.CACHE_DISTRIBUTE).createStage(stageContext));
+        stages.add(new CacheFileUpdateStage(stageContext));
     }
 
     protected void createInstallStages() {
@@ -166,8 +174,7 @@ public abstract class AbstractServiceJobFactory extends AbstractJobFactory {
             }
 
             StageContext stageContext = createStageContext(serviceName, componentName, hostnames);
-            stagePOList.add(
-                    StageFactories.getStageFactory(StageType.COMPONENT_INSTALL).createStage(stageContext));
+            stages.add(new ComponentInstallStage(stageContext));
         }
     }
 
@@ -189,8 +196,7 @@ public abstract class AbstractServiceJobFactory extends AbstractJobFactory {
             }
 
             StageContext stageContext = createStageContext(serviceName, componentName, hostnames);
-            stagePOList.add(
-                    StageFactories.getStageFactory(StageType.COMPONENT_START).createStage(stageContext));
+            stages.add(new ComponentStartStage(stageContext));
         }
     }
 
@@ -212,8 +218,7 @@ public abstract class AbstractServiceJobFactory extends AbstractJobFactory {
             }
 
             StageContext stageContext = createStageContext(serviceName, componentName, hostnames);
-            stagePOList.add(
-                    StageFactories.getStageFactory(StageType.COMPONENT_STOP).createStage(stageContext));
+            stages.add(new ComponentStopStage(stageContext));
         }
     }
 
@@ -235,8 +240,7 @@ public abstract class AbstractServiceJobFactory extends AbstractJobFactory {
             }
 
             StageContext stageContext = createStageContext(serviceName, componentName, List.of(hostnames.get(0)));
-            stagePOList.add(
-                    StageFactories.getStageFactory(StageType.COMPONENT_CHECK).createStage(stageContext));
+            stages.add(new ComponentCheckStage(stageContext));
         }
     }
 
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/cluster/ClusterCreateJobRunner.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/ClusterCreateJob.java
similarity index 60%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/cluster/ClusterCreateJobRunner.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/ClusterCreateJob.java
index 09a8d71..4282a2c 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/cluster/ClusterCreateJobRunner.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/ClusterCreateJob.java
@@ -16,55 +16,44 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.runner.cluster;
+package org.apache.bigtop.manager.server.command.job;
 
-import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.common.enums.MaintainState;
 import org.apache.bigtop.manager.dao.po.ClusterPO;
+import org.apache.bigtop.manager.dao.po.JobPO;
 import org.apache.bigtop.manager.dao.po.StagePO;
 import org.apache.bigtop.manager.dao.po.TaskPO;
-import org.apache.bigtop.manager.dao.repository.ClusterRepository;
-import org.apache.bigtop.manager.dao.repository.JobRepository;
-import org.apache.bigtop.manager.dao.repository.StageRepository;
-import org.apache.bigtop.manager.dao.repository.TaskRepository;
-import org.apache.bigtop.manager.server.command.CommandIdentifier;
-import org.apache.bigtop.manager.server.command.job.runner.AbstractJobRunner;
-import org.apache.bigtop.manager.server.enums.CommandLevel;
+import org.apache.bigtop.manager.server.command.stage.CacheFileUpdateStage;
+import org.apache.bigtop.manager.server.command.stage.HostCheckStage;
+import org.apache.bigtop.manager.server.command.stage.Stage;
+import org.apache.bigtop.manager.server.command.stage.StageContext;
+import org.apache.bigtop.manager.server.command.task.Task;
+import org.apache.bigtop.manager.server.holder.SpringContextHolder;
 import org.apache.bigtop.manager.server.model.converter.ClusterConverter;
 import org.apache.bigtop.manager.server.model.dto.ClusterDTO;
 import org.apache.bigtop.manager.server.model.dto.CommandDTO;
 import org.apache.bigtop.manager.server.service.ClusterService;
 
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Scope;
+public class ClusterCreateJob extends AbstractJob {
 
-import lombok.extern.slf4j.Slf4j;
-
-import jakarta.annotation.Resource;
-
-@Slf4j
-@org.springframework.stereotype.Component
-@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class ClusterCreateJobRunner extends AbstractJobRunner {
-
-    @Resource
     private ClusterService clusterService;
 
-    @Resource
-    private ClusterRepository clusterRepository;
-
-    @Resource
-    private JobRepository jobRepository;
+    public ClusterCreateJob(JobContext jobContext) {
+        super(jobContext);
+    }
 
-    @Resource
-    private StageRepository stageRepository;
+    @Override
+    protected void injectBeans() {
+        super.injectBeans();
 
-    @Resource
-    private TaskRepository taskRepository;
+        this.clusterService = SpringContextHolder.getBean(ClusterService.class);
+    }
 
     @Override
-    public CommandIdentifier getCommandIdentifier() {
-        return new CommandIdentifier(CommandLevel.CLUSTER, Command.CREATE);
+    protected void createStages() {
+        StageContext stageContext = StageContext.fromCommandDTO(jobContext.getCommandDTO());
+        stages.add(new HostCheckStage(stageContext));
+        stages.add(new CacheFileUpdateStage(stageContext));
     }
 
     @Override
@@ -72,7 +61,7 @@ public class ClusterCreateJobRunner extends AbstractJobRunner {
         super.beforeRun();
 
         // Save cluster
-        CommandDTO commandDTO = getCommandDTO();
+        CommandDTO commandDTO = jobContext.getCommandDTO();
         ClusterDTO clusterDTO = ClusterConverter.INSTANCE.fromCommand2DTO(commandDTO.getClusterCommand());
         clusterService.save(clusterDTO);
     }
@@ -81,7 +70,7 @@ public class ClusterCreateJobRunner extends AbstractJobRunner {
     public void onSuccess() {
         super.onSuccess();
 
-        CommandDTO commandDTO = getCommandDTO();
+        CommandDTO commandDTO = jobContext.getCommandDTO();
         ClusterPO clusterPO = clusterRepository
                 .findByClusterName(commandDTO.getClusterCommand().getClusterName())
                 .orElse(new ClusterPO());
@@ -91,17 +80,25 @@ public class ClusterCreateJobRunner extends AbstractJobRunner {
         clusterRepository.save(clusterPO);
 
         // Link job to cluster after cluster successfully added
+        JobPO jobPO = getJobPO();
         jobPO.setClusterPO(clusterPO);
         jobRepository.save(jobPO);
 
-        for (StagePO stagePO : jobPO.getStagePOList()) {
+        for (Stage stage : getStages()) {
+            StagePO stagePO = stage.getStagePO();
             stagePO.setClusterPO(clusterPO);
             stageRepository.save(stagePO);
 
-            for (TaskPO taskPO : stagePO.getTaskPOList()) {
+            for (Task task : stage.getTasks()) {
+                TaskPO taskPO = task.getTaskPO();
                 taskPO.setClusterPO(clusterPO);
                 taskRepository.save(taskPO);
             }
         }
     }
+
+    @Override
+    public String getName() {
+        return "Create cluster";
+    }
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/host/HostAddJobRunner.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/HostAddJob.java
similarity index 55%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/host/HostAddJobRunner.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/HostAddJob.java
index 95e5dba..553787a 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/host/HostAddJobRunner.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/HostAddJob.java
@@ -16,46 +16,54 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.runner.host;
+package org.apache.bigtop.manager.server.command.job;
 
-import org.apache.bigtop.manager.common.enums.Command;
-import org.apache.bigtop.manager.server.command.CommandIdentifier;
-import org.apache.bigtop.manager.server.command.job.runner.AbstractJobRunner;
-import org.apache.bigtop.manager.server.enums.CommandLevel;
+import org.apache.bigtop.manager.server.command.stage.CacheFileUpdateStage;
+import org.apache.bigtop.manager.server.command.stage.HostCheckStage;
+import org.apache.bigtop.manager.server.command.stage.StageContext;
+import org.apache.bigtop.manager.server.holder.SpringContextHolder;
 import org.apache.bigtop.manager.server.model.dto.CommandDTO;
 import org.apache.bigtop.manager.server.model.dto.command.HostCommandDTO;
 import org.apache.bigtop.manager.server.service.HostService;
 
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Scope;
-
-import lombok.extern.slf4j.Slf4j;
-
-import jakarta.annotation.Resource;
 import java.util.List;
 
-@Slf4j
-@org.springframework.stereotype.Component
-@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class HostAddJobRunner extends AbstractJobRunner {
+public class HostAddJob extends AbstractJob {
 
-    @Resource
     private HostService hostService;
 
+    public HostAddJob(JobContext jobContext) {
+        super(jobContext);
+    }
+
     @Override
-    public CommandIdentifier getCommandIdentifier() {
-        return new CommandIdentifier(CommandLevel.HOST, Command.INSTALL);
+    protected void injectBeans() {
+        super.injectBeans();
+
+        this.hostService = SpringContextHolder.getBean(HostService.class);
+    }
+
+    @Override
+    protected void createStages() {
+        StageContext stageContext = StageContext.fromCommandDTO(jobContext.getCommandDTO());
+        stages.add(new HostCheckStage(stageContext));
+        stages.add(new CacheFileUpdateStage(stageContext));
     }
 
     @Override
     public void onSuccess() {
         super.onSuccess();
 
-        CommandDTO commandDTO = getCommandDTO();
+        CommandDTO commandDTO = jobContext.getCommandDTO();
         List<HostCommandDTO> hostCommands = commandDTO.getHostCommands();
 
         List<String> hostnames =
                 hostCommands.stream().map(HostCommandDTO::getHostname).toList();
-        hostService.batchSave(jobPO.getClusterPO().getId(), hostnames);
+        hostService.batchSave(commandDTO.getClusterId(), hostnames);
+    }
+
+    @Override
+    public String getName() {
+        return "Add host";
     }
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/JobFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/Job.java
similarity index 68%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/JobFactory.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/Job.java
index 89e3953..8f086e1 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/JobFactory.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/Job.java
@@ -16,14 +16,30 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.factory;
+package org.apache.bigtop.manager.server.command.job;
 
 import org.apache.bigtop.manager.dao.po.JobPO;
-import org.apache.bigtop.manager.server.command.CommandIdentifier;
+import org.apache.bigtop.manager.server.command.stage.Stage;
 
-public interface JobFactory {
+import java.util.List;
 
-    CommandIdentifier getCommandIdentifier();
+public interface Job {
 
-    JobPO createJob(JobContext jobContext);
+    String getName();
+
+    void beforeRun();
+
+    void run();
+
+    void onSuccess();
+
+    void onFailure();
+
+    JobContext getJobContext();
+
+    List<Stage> getStages();
+
+    void loadJobPO(JobPO jobPO);
+
+    JobPO getJobPO();
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/JobContext.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/JobContext.java
similarity index 93%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/JobContext.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/JobContext.java
index c67527f..5b9206d 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/JobContext.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/JobContext.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.factory;
+package org.apache.bigtop.manager.server.command.job;
 
 import org.apache.bigtop.manager.server.model.dto.CommandDTO;
 
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/CommandValidator.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/ServiceConfigureJob.java
similarity index 68%
copy from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/CommandValidator.java
copy to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/ServiceConfigureJob.java
index 0fe4dba..9dad58a 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/CommandValidator.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/ServiceConfigureJob.java
@@ -16,15 +16,21 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.validator;
+package org.apache.bigtop.manager.server.command.job;
 
-import org.apache.bigtop.manager.server.command.CommandIdentifier;
+public class ServiceConfigureJob extends AbstractServiceJob {
 
-import java.util.List;
+    public ServiceConfigureJob(JobContext jobContext) {
+        super(jobContext);
+    }
 
-public interface CommandValidator {
+    @Override
+    protected void createStages() {
+        super.createCacheStage();
+    }
 
-    List<CommandIdentifier> getCommandIdentifiers();
-
-    void validate(ValidatorContext context);
+    @Override
+    public String getName() {
+        return "Configure services";
+    }
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/service/ServiceInstallJobRunner.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/ServiceInstallJob.java
similarity index 62%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/service/ServiceInstallJobRunner.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/ServiceInstallJob.java
index e54c79f..d97b209 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/service/ServiceInstallJobRunner.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/ServiceInstallJob.java
@@ -16,23 +16,17 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.runner.service;
+package org.apache.bigtop.manager.server.command.job;
 
-import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.common.enums.MaintainState;
 import org.apache.bigtop.manager.dao.po.ClusterPO;
 import org.apache.bigtop.manager.dao.po.ComponentPO;
 import org.apache.bigtop.manager.dao.po.HostComponentPO;
 import org.apache.bigtop.manager.dao.po.HostPO;
 import org.apache.bigtop.manager.dao.po.ServicePO;
-import org.apache.bigtop.manager.dao.repository.ClusterRepository;
-import org.apache.bigtop.manager.dao.repository.ComponentRepository;
-import org.apache.bigtop.manager.dao.repository.HostComponentRepository;
 import org.apache.bigtop.manager.dao.repository.HostRepository;
 import org.apache.bigtop.manager.dao.repository.ServiceRepository;
-import org.apache.bigtop.manager.server.command.CommandIdentifier;
-import org.apache.bigtop.manager.server.command.job.runner.AbstractJobRunner;
-import org.apache.bigtop.manager.server.enums.CommandLevel;
+import org.apache.bigtop.manager.server.holder.SpringContextHolder;
 import org.apache.bigtop.manager.server.model.converter.ComponentConverter;
 import org.apache.bigtop.manager.server.model.converter.ServiceConverter;
 import org.apache.bigtop.manager.server.model.dto.CommandDTO;
@@ -43,47 +37,88 @@ import org.apache.bigtop.manager.server.model.dto.command.ServiceCommandDTO;
 import org.apache.bigtop.manager.server.service.ConfigService;
 import org.apache.bigtop.manager.server.utils.StackUtils;
 
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Scope;
-
-import lombok.extern.slf4j.Slf4j;
-
-import jakarta.annotation.Resource;
+import java.util.ArrayList;
 import java.util.List;
 
-@Slf4j
-@org.springframework.stereotype.Component
-@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class ServiceInstallJobRunner extends AbstractJobRunner {
+public class ServiceInstallJob extends AbstractServiceJob {
 
-    @Resource
     private ConfigService configService;
+    private ServiceRepository serviceRepository;
+    private HostRepository hostRepository;
 
-    @Resource
-    private ClusterRepository clusterRepository;
+    public ServiceInstallJob(JobContext jobContext) {
+        super(jobContext);
+    }
 
-    @Resource
-    private ServiceRepository serviceRepository;
+    @Override
+    protected void injectBeans() {
+        super.injectBeans();
 
-    @Resource
-    private ComponentRepository componentRepository;
+        this.configService = SpringContextHolder.getBean(ConfigService.class);
+        this.serviceRepository = SpringContextHolder.getBean(ServiceRepository.class);
+        this.hostRepository = SpringContextHolder.getBean(HostRepository.class);
+    }
 
-    @Resource
-    private HostRepository hostRepository;
+    @Override
+    protected void createStages() {
+        // Install components
+        super.createInstallStages();
+
+        // Update cache files after installed
+        super.createCacheStage();
+
+        // Start all master components
+        super.createStartStages();
+
+        // Check all master components after started
+        super.createCheckStages();
+    }
 
-    @Resource
-    private HostComponentRepository hostComponentRepository;
+    @Override
+    protected List<String> getComponentNames() {
+        List<String> componentNames = new ArrayList<>();
+        for (ServiceCommandDTO serviceCommand : jobContext.getCommandDTO().getServiceCommands()) {
+            List<ComponentHostDTO> componentHosts = serviceCommand.getComponentHosts();
+            for (ComponentHostDTO componentHost : componentHosts) {
+                String componentName = componentHost.getComponentName();
+                componentNames.add(componentName);
+            }
+        }
+
+        return componentNames;
+    }
 
     @Override
-    public CommandIdentifier getCommandIdentifier() {
-        return new CommandIdentifier(CommandLevel.SERVICE, Command.INSTALL);
+    protected List<String> findHostnamesByComponentName(String componentName) {
+        for (ServiceCommandDTO serviceCommand : jobContext.getCommandDTO().getServiceCommands()) {
+            List<ComponentHostDTO> componentHosts = serviceCommand.getComponentHosts();
+            for (ComponentHostDTO componentHost : componentHosts) {
+                if (componentHost.getComponentName().equals(componentName)) {
+                    List<String> hostnames = new ArrayList<>(componentHost.getHostnames());
+                    if (serviceCommand.getInstalled()) {
+                        List<String> existHostnames = hostComponentRepository
+                                .findAllByComponentPOClusterPOIdAndComponentPOComponentNameAndHostPOHostnameIn(
+                                        clusterPO.getId(), componentName, hostnames)
+                                .stream()
+                                .map(hostComponent -> hostComponent.getHostPO().getHostname())
+                                .toList();
+
+                        hostnames.removeAll(existHostnames);
+                    }
+
+                    return hostnames;
+                }
+            }
+        }
+
+        return new ArrayList<>();
     }
 
     @Override
     public void beforeRun() {
         super.beforeRun();
 
-        CommandDTO commandDTO = getCommandDTO();
+        CommandDTO commandDTO = jobContext.getCommandDTO();
         List<ServiceCommandDTO> serviceCommands = commandDTO.getServiceCommands();
         Long clusterId = commandDTO.getClusterId();
 
@@ -96,7 +131,7 @@ public class ServiceInstallJobRunner extends AbstractJobRunner {
     }
 
     private void upsertService(ServicePO servicePO, ServiceCommandDTO serviceCommand) {
-        CommandDTO commandDTO = getCommandDTO();
+        CommandDTO commandDTO = jobContext.getCommandDTO();
         Long clusterId = commandDTO.getClusterId();
         String serviceName = serviceCommand.getServiceName();
         ClusterPO clusterPO = clusterRepository.getReferenceById(clusterId);
@@ -104,7 +139,7 @@ public class ServiceInstallJobRunner extends AbstractJobRunner {
         String stackName = clusterPO.getStackPO().getStackName();
         String stackVersion = clusterPO.getStackPO().getStackVersion();
 
-        // 1. Persist service
+        // 1. Persist service and components
         if (servicePO == null) {
             ServiceDTO serviceDTO = StackUtils.getServiceDTO(stackName, stackVersion, serviceName);
             servicePO = ServiceConverter.INSTANCE.fromDTO2PO(serviceDTO, clusterPO);
@@ -142,4 +177,9 @@ public class ServiceInstallJobRunner extends AbstractJobRunner {
             }
         }
     }
+
+    @Override
+    public String getName() {
+        return "Install services";
+    }
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/CommandValidator.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/ServiceRestartJob.java
similarity index 66%
copy from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/CommandValidator.java
copy to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/ServiceRestartJob.java
index 0fe4dba..53215d0 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/CommandValidator.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/ServiceRestartJob.java
@@ -16,15 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.validator;
+package org.apache.bigtop.manager.server.command.job;
 
-import org.apache.bigtop.manager.server.command.CommandIdentifier;
+public class ServiceRestartJob extends AbstractServiceJob {
 
-import java.util.List;
+    public ServiceRestartJob(JobContext jobContext) {
+        super(jobContext);
+    }
 
-public interface CommandValidator {
+    @Override
+    protected void createStages() {
+        super.createStopStages();
 
-    List<CommandIdentifier> getCommandIdentifiers();
+        super.createStartStages();
+    }
 
-    void validate(ValidatorContext context);
+    @Override
+    public String getName() {
+        return "Restart services";
+    }
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/CommandValidator.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/ServiceStartJob.java
similarity index 68%
copy from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/CommandValidator.java
copy to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/ServiceStartJob.java
index 0fe4dba..38e7a4c 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/CommandValidator.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/ServiceStartJob.java
@@ -16,15 +16,21 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.validator;
+package org.apache.bigtop.manager.server.command.job;
 
-import org.apache.bigtop.manager.server.command.CommandIdentifier;
+public class ServiceStartJob extends AbstractServiceJob {
 
-import java.util.List;
+    public ServiceStartJob(JobContext jobContext) {
+        super(jobContext);
+    }
 
-public interface CommandValidator {
+    @Override
+    protected void createStages() {
+        super.createStartStages();
+    }
 
-    List<CommandIdentifier> getCommandIdentifiers();
-
-    void validate(ValidatorContext context);
+    @Override
+    public String getName() {
+        return "Start services";
+    }
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/CommandValidator.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/ServiceStopJob.java
similarity index 68%
copy from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/CommandValidator.java
copy to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/ServiceStopJob.java
index 0fe4dba..13f9dbd 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/CommandValidator.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/ServiceStopJob.java
@@ -16,15 +16,21 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.validator;
+package org.apache.bigtop.manager.server.command.job;
 
-import org.apache.bigtop.manager.server.command.CommandIdentifier;
+public class ServiceStopJob extends AbstractServiceJob {
 
-import java.util.List;
+    public ServiceStopJob(JobContext jobContext) {
+        super(jobContext);
+    }
 
-public interface CommandValidator {
+    @Override
+    protected void createStages() {
+        super.createStopStages();
+    }
 
-    List<CommandIdentifier> getCommandIdentifiers();
-
-    void validate(ValidatorContext context);
+    @Override
+    public String getName() {
+        return "Stop services";
+    }
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/AbstractJobFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/AbstractJobFactory.java
deleted file mode 100644
index dc7641f..0000000
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/AbstractJobFactory.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * 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
- *
- *    https://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.bigtop.manager.server.command.job.factory;
-
-import org.apache.bigtop.manager.common.enums.JobState;
-import org.apache.bigtop.manager.common.utils.JsonUtils;
-import org.apache.bigtop.manager.dao.po.ClusterPO;
-import org.apache.bigtop.manager.dao.po.JobPO;
-import org.apache.bigtop.manager.dao.po.StagePO;
-import org.apache.bigtop.manager.dao.po.TaskPO;
-import org.apache.bigtop.manager.dao.repository.ClusterRepository;
-import org.apache.bigtop.manager.dao.repository.JobRepository;
-import org.apache.bigtop.manager.dao.repository.StageRepository;
-import org.apache.bigtop.manager.dao.repository.TaskRepository;
-
-import jakarta.annotation.Resource;
-import java.util.ArrayList;
-import java.util.List;
-
-public abstract class AbstractJobFactory implements JobFactory {
-
-    @Resource
-    private ClusterRepository clusterRepository;
-
-    @Resource
-    private JobRepository jobRepository;
-
-    @Resource
-    private StageRepository stageRepository;
-
-    @Resource
-    private TaskRepository taskRepository;
-
-    protected JobContext jobContext;
-
-    protected ClusterPO clusterPO;
-
-    protected JobPO jobPO;
-
-    protected List<StagePO> stagePOList = new ArrayList<>();
-
-    @Override
-    public JobPO createJob(JobContext jobContext) {
-        this.jobContext = jobContext;
-
-        // Create and init job
-        initJob();
-
-        // Create stages and tasks for job
-        createStagesAndTasks();
-
-        // Save job
-        saveJob();
-
-        return this.jobPO;
-    }
-
-    protected abstract void createStagesAndTasks();
-
-    private void initJob() {
-        Long clusterId = jobContext.getCommandDTO().getClusterId();
-        this.clusterPO = clusterId == null ? new ClusterPO() : clusterRepository.getReferenceById(clusterId);
-
-        this.jobPO = new JobPO();
-        jobPO.setName(jobContext.getCommandDTO().getContext());
-        jobPO.setState(JobState.PENDING);
-        jobPO.setClusterPO(clusterPO.getId() == null ? null : clusterPO);
-        jobPO.setContext(JsonUtils.writeAsString(jobContext));
-        jobPO.setStagePOList(stagePOList);
-    }
-
-    protected void saveJob() {
-        jobRepository.save(jobPO);
-
-        for (int i = 0; i < jobPO.getStagePOList().size(); i++) {
-            StagePO stagePO = jobPO.getStagePOList().get(i);
-            stagePO.setClusterPO(clusterPO.getId() == null ? null : clusterPO);
-            stagePO.setJobPO(jobPO);
-            stagePO.setOrder(i + 1);
-            stagePO.setState(JobState.PENDING);
-            stageRepository.save(stagePO);
-
-            for (TaskPO taskPO : stagePO.getTaskPOList()) {
-                taskPO.setClusterPO(clusterPO.getId() == null ? null : clusterPO);
-                taskPO.setJobPO(jobPO);
-                taskPO.setStagePO(stagePO);
-                taskPO.setState(JobState.PENDING);
-                taskRepository.save(taskPO);
-            }
-        }
-    }
-}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/cluster/ClusterCreateJobFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/cluster/ClusterCreateJobFactory.java
deleted file mode 100644
index 1eaf5f0..0000000
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/cluster/ClusterCreateJobFactory.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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
- *
- *    https://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.bigtop.manager.server.command.job.factory.cluster;
-
-import org.apache.bigtop.manager.common.enums.Command;
-import org.apache.bigtop.manager.common.utils.JsonUtils;
-import org.apache.bigtop.manager.server.command.CommandIdentifier;
-import org.apache.bigtop.manager.server.command.stage.factory.StageContext;
-import org.apache.bigtop.manager.server.command.stage.factory.StageFactories;
-import org.apache.bigtop.manager.server.command.stage.factory.StageType;
-import org.apache.bigtop.manager.server.enums.CommandLevel;
-
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Scope;
-
-import lombok.extern.slf4j.Slf4j;
-
-@Slf4j
-@org.springframework.stereotype.Component
-@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class ClusterCreateJobFactory extends AbstractClusterJobFactory {
-
-    @Override
-    public CommandIdentifier getCommandIdentifier() {
-        return new CommandIdentifier(CommandLevel.CLUSTER, Command.CREATE);
-    }
-
-    @Override
-    public void createStagesAndTasks() {
-        StageContext stageContext = StageContext.fromPayload(JsonUtils.writeAsString(jobContext.getCommandDTO()));
-        stagePOList.add(StageFactories.getStageFactory(StageType.HOST_CHECK).createStage(stageContext));
-        stagePOList.add(
-                StageFactories.getStageFactory(StageType.CACHE_DISTRIBUTE).createStage(stageContext));
-    }
-}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/host/HostAddJobFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/host/HostAddJobFactory.java
deleted file mode 100644
index 99645e5..0000000
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/host/HostAddJobFactory.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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
- *
- *    https://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.bigtop.manager.server.command.job.factory.host;
-
-import org.apache.bigtop.manager.common.enums.Command;
-import org.apache.bigtop.manager.common.utils.JsonUtils;
-import org.apache.bigtop.manager.server.command.CommandIdentifier;
-import org.apache.bigtop.manager.server.command.stage.factory.StageContext;
-import org.apache.bigtop.manager.server.command.stage.factory.StageFactories;
-import org.apache.bigtop.manager.server.command.stage.factory.StageType;
-import org.apache.bigtop.manager.server.enums.CommandLevel;
-
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Scope;
-
-import lombok.extern.slf4j.Slf4j;
-
-@Slf4j
-@org.springframework.stereotype.Component
-@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class HostAddJobFactory extends AbstractHostJobFactory {
-
-    @Override
-    public CommandIdentifier getCommandIdentifier() {
-        return new CommandIdentifier(CommandLevel.HOST, Command.INSTALL);
-    }
-
-    public void createStagesAndTasks() {
-        StageContext stageContext = StageContext.fromPayload(JsonUtils.writeAsString(jobContext.getCommandDTO()));
-        stagePOList.add(StageFactories.getStageFactory(StageType.HOST_CHECK).createStage(stageContext));
-        stagePOList.add(
-                StageFactories.getStageFactory(StageType.CACHE_DISTRIBUTE).createStage(stageContext));
-    }
-}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/service/ServiceInstallJobFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/service/ServiceInstallJobFactory.java
deleted file mode 100644
index 31d2877..0000000
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/factory/service/ServiceInstallJobFactory.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * 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
- *
- *    https://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.bigtop.manager.server.command.job.factory.service;
-
-import org.apache.bigtop.manager.common.enums.Command;
-import org.apache.bigtop.manager.server.command.CommandIdentifier;
-import org.apache.bigtop.manager.server.enums.CommandLevel;
-import org.apache.bigtop.manager.server.model.dto.ComponentHostDTO;
-import org.apache.bigtop.manager.server.model.dto.command.ServiceCommandDTO;
-
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Scope;
-
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@Slf4j
-@org.springframework.stereotype.Component
-@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class ServiceInstallJobFactory extends AbstractServiceJobFactory {
-
-    @Override
-    public CommandIdentifier getCommandIdentifier() {
-        return new CommandIdentifier(CommandLevel.SERVICE, Command.INSTALL);
-    }
-
-    /**
-     * create job and persist it to database
-     */
-    @Override
-    protected void createStagesAndTasks() {
-        super.initAttrs();
-
-        // Install components
-        super.createInstallStages();
-
-        // Distribute caches after installed
-        super.createCacheStage();
-
-        // Start all master components
-        super.createStartStages();
-
-        // Check all master components after started
-        super.createCheckStages();
-    }
-
-    @Override
-    protected List<String> getComponentNames() {
-        List<String> componentNames = new ArrayList<>();
-        for (ServiceCommandDTO serviceCommand : jobContext.getCommandDTO().getServiceCommands()) {
-            List<ComponentHostDTO> componentHosts = serviceCommand.getComponentHosts();
-            for (ComponentHostDTO componentHost : componentHosts) {
-                String componentName = componentHost.getComponentName();
-                componentNames.add(componentName);
-            }
-        }
-
-        return componentNames;
-    }
-
-    @Override
-    protected List<String> findHostnamesByComponentName(String componentName) {
-        for (ServiceCommandDTO serviceCommand : jobContext.getCommandDTO().getServiceCommands()) {
-            List<ComponentHostDTO> componentHosts = serviceCommand.getComponentHosts();
-            for (ComponentHostDTO componentHost : componentHosts) {
-                if (componentHost.getComponentName().equals(componentName)) {
-                    List<String> hostnames = new ArrayList<>(componentHost.getHostnames());
-                    List<String> existHostnames = hostComponentRepository
-                            .findAllByComponentPOClusterPOIdAndComponentPOComponentNameAndHostPOHostnameIn(
-                                    clusterPO.getId(), componentName, hostnames)
-                            .stream()
-                            .map(hostComponent -> hostComponent.getHostPO().getHostname())
-                            .toList();
-
-                    hostnames.removeAll(existHostnames);
-                    return hostnames;
-                }
-            }
-        }
-
-        return new ArrayList<>();
-    }
-}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/AbstractJobRunner.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/AbstractJobRunner.java
deleted file mode 100644
index 4acd7ec..0000000
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/AbstractJobRunner.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * 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
- *
- *    https://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.bigtop.manager.server.command.job.runner;
-
-import org.apache.bigtop.manager.common.enums.JobState;
-import org.apache.bigtop.manager.dao.po.JobPO;
-import org.apache.bigtop.manager.dao.po.StagePO;
-import org.apache.bigtop.manager.dao.po.TaskPO;
-import org.apache.bigtop.manager.dao.repository.JobRepository;
-import org.apache.bigtop.manager.dao.repository.StageRepository;
-import org.apache.bigtop.manager.dao.repository.TaskRepository;
-import org.apache.bigtop.manager.server.command.job.factory.JobContext;
-import org.apache.bigtop.manager.server.command.stage.runner.StageRunner;
-import org.apache.bigtop.manager.server.command.stage.runner.StageRunners;
-import org.apache.bigtop.manager.server.model.dto.CommandDTO;
-
-import jakarta.annotation.Resource;
-import java.util.Comparator;
-import java.util.List;
-import java.util.concurrent.LinkedBlockingQueue;
-
-public abstract class AbstractJobRunner implements JobRunner {
-
-    @Resource
-    private JobRepository jobRepository;
-
-    @Resource
-    private StageRepository stageRepository;
-
-    @Resource
-    private TaskRepository taskRepository;
-
-    protected JobPO jobPO;
-
-    protected JobContext jobContext;
-
-    @Override
-    public void setJob(JobPO jobPO) {
-        this.jobPO = jobPO;
-    }
-
-    @Override
-    public void setJobContext(JobContext jobContext) {
-        this.jobContext = jobContext;
-    }
-
-    @Override
-    public void run() {
-        beforeRun();
-
-        // Sort stage
-        List<StagePO> stagePOList = jobPO.getStagePOList();
-        stagePOList.sort(Comparator.comparingInt(StagePO::getOrder));
-
-        boolean success = true;
-        LinkedBlockingQueue<StagePO> queue = new LinkedBlockingQueue<>(stagePOList);
-        while (!queue.isEmpty()) {
-            StagePO stagePO = queue.poll();
-            StageRunner runner = StageRunners.getStageRunner(stagePO);
-            runner.run();
-
-            if (stagePO.getState() == JobState.FAILED) {
-                success = false;
-                break;
-            }
-        }
-
-        if (success) {
-            onSuccess();
-        } else {
-            onFailure();
-        }
-    }
-
-    @Override
-    public void beforeRun() {
-        jobPO.setState(JobState.PROCESSING);
-        jobRepository.save(jobPO);
-    }
-
-    @Override
-    public void onSuccess() {
-        jobPO.setState(JobState.SUCCESSFUL);
-        jobRepository.save(jobPO);
-    }
-
-    @Override
-    public void onFailure() {
-        jobPO.setState(JobState.FAILED);
-        jobRepository.save(jobPO);
-
-        for (StagePO stagePO : jobPO.getStagePOList()) {
-            if (stagePO.getState() == JobState.PENDING) {
-                stagePO.setState(JobState.CANCELED);
-                stageRepository.save(stagePO);
-
-                for (TaskPO taskPO : stagePO.getTaskPOList()) {
-                    taskPO.setState(JobState.CANCELED);
-                    taskRepository.save(taskPO);
-                }
-            }
-        }
-    }
-
-    protected CommandDTO getCommandDTO() {
-        return jobContext.getCommandDTO();
-    }
-}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/JobRunner.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/JobRunner.java
deleted file mode 100644
index c0f10b7..0000000
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/JobRunner.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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
- *
- *    https://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.bigtop.manager.server.command.job.runner;
-
-import org.apache.bigtop.manager.dao.po.JobPO;
-import org.apache.bigtop.manager.server.command.CommandIdentifier;
-import org.apache.bigtop.manager.server.command.job.factory.JobContext;
-
-/**
- * Interface for running jobs in the application.
- * A job represents a unit of work, and this interface provides methods for managing and running these jobs.
- */
-public interface JobRunner {
-
-    /**
-     * Get the identifier of the command that this runner is responsible for.
-     *
-     * @return The identifier of the command.
-     */
-    CommandIdentifier getCommandIdentifier();
-
-    /**
-     * Set the job that this runner will manage.
-     *
-     * @param jobPO The job to be managed by this runner.
-     */
-    void setJob(JobPO jobPO);
-
-    /**
-     * Set the context for the job. The context may contain additional information necessary for running the job.
-     *
-     * @param jobContext The context for the job.
-     */
-    void setJobContext(JobContext jobContext);
-
-    /**
-     * Method to be called before running the job. Can be used for setup and preparation.
-     */
-    void beforeRun();
-
-    /**
-     * Run the job. This is where the main logic of the job should be implemented.
-     */
-    void run();
-
-    /**
-     * Method to be called after the job has successfully run. Can be used for cleanup and finalization.
-     */
-    void onSuccess();
-
-    /**
-     * Method to be called if the job fails to run. Can be used for error handling and recovery.
-     */
-    void onFailure();
-}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/JobRunners.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/JobRunners.java
deleted file mode 100644
index 73f3474..0000000
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/JobRunners.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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
- *
- *    https://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.bigtop.manager.server.command.job.runner;
-
-import org.apache.bigtop.manager.common.utils.JsonUtils;
-import org.apache.bigtop.manager.dao.po.JobPO;
-import org.apache.bigtop.manager.server.command.CommandIdentifier;
-import org.apache.bigtop.manager.server.command.job.factory.JobContext;
-import org.apache.bigtop.manager.server.enums.ApiExceptionEnum;
-import org.apache.bigtop.manager.server.exception.ApiException;
-import org.apache.bigtop.manager.server.holder.SpringContextHolder;
-import org.apache.bigtop.manager.server.model.dto.CommandDTO;
-
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-@Slf4j
-public class JobRunners {
-
-    private static final AtomicBoolean LOADED = new AtomicBoolean(false);
-
-    private static final Map<CommandIdentifier, String> JOB_RUNNERS = new HashMap<>();
-
-    public static JobRunner getJobRunner(JobPO jobPO) {
-        if (!LOADED.get()) {
-            load();
-        }
-
-        JobContext jobContext = JsonUtils.readFromString(jobPO.getContext(), JobContext.class);
-        CommandDTO commandDTO = jobContext.getCommandDTO();
-        CommandIdentifier identifier = new CommandIdentifier(commandDTO.getCommandLevel(), commandDTO.getCommand());
-        if (!JOB_RUNNERS.containsKey(identifier)) {
-            throw new ApiException(
-                    ApiExceptionEnum.COMMAND_NOT_SUPPORTED,
-                    identifier.getCommand().name().toLowerCase(),
-                    identifier.getCommandLevel().toLowerCase());
-        }
-
-        String beanName = JOB_RUNNERS.get(identifier);
-        JobRunner runner = SpringContextHolder.getApplicationContext().getBean(beanName, JobRunner.class);
-        runner.setJob(jobPO);
-        runner.setJobContext(jobContext);
-
-        return runner;
-    }
-
-    private static synchronized void load() {
-        if (LOADED.get()) {
-            return;
-        }
-
-        for (Map.Entry<String, JobRunner> entry :
-                SpringContextHolder.getJobRunners().entrySet()) {
-            String beanName = entry.getKey();
-            JobRunner jobRunner = entry.getValue();
-            if (JOB_RUNNERS.containsKey(jobRunner.getCommandIdentifier())) {
-                log.error("Duplicate JobRunner with identifier: {}", jobRunner.getCommandIdentifier());
-                continue;
-            }
-
-            JOB_RUNNERS.put(jobRunner.getCommandIdentifier(), beanName);
-            log.info(
-                    "Load JobRunner: {} with identifier: {}",
-                    jobRunner.getClass().getName(),
-                    jobRunner.getCommandIdentifier());
-        }
-
-        LOADED.set(true);
-    }
-}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/component/ComponentInstallJobRunner.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/component/ComponentInstallJobRunner.java
deleted file mode 100644
index ecc07fa..0000000
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/component/ComponentInstallJobRunner.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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
- *
- *    https://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.bigtop.manager.server.command.job.runner.component;
-
-import org.apache.bigtop.manager.common.enums.Command;
-import org.apache.bigtop.manager.server.command.CommandIdentifier;
-import org.apache.bigtop.manager.server.command.job.runner.AbstractJobRunner;
-import org.apache.bigtop.manager.server.enums.CommandLevel;
-
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Scope;
-
-import lombok.extern.slf4j.Slf4j;
-
-@Slf4j
-@org.springframework.stereotype.Component
-@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class ComponentInstallJobRunner extends AbstractJobRunner {
-
-    @Override
-    public CommandIdentifier getCommandIdentifier() {
-        return new CommandIdentifier(CommandLevel.COMPONENT, Command.INSTALL);
-    }
-}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/component/ComponentRestartJobRunner.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/component/ComponentRestartJobRunner.java
deleted file mode 100644
index f8b1aa5..0000000
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/component/ComponentRestartJobRunner.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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
- *
- *    https://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.bigtop.manager.server.command.job.runner.component;
-
-import org.apache.bigtop.manager.common.enums.Command;
-import org.apache.bigtop.manager.server.command.CommandIdentifier;
-import org.apache.bigtop.manager.server.command.job.runner.AbstractJobRunner;
-import org.apache.bigtop.manager.server.enums.CommandLevel;
-
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Scope;
-
-import lombok.extern.slf4j.Slf4j;
-
-@Slf4j
-@org.springframework.stereotype.Component
-@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class ComponentRestartJobRunner extends AbstractJobRunner {
-
-    @Override
-    public CommandIdentifier getCommandIdentifier() {
-        return new CommandIdentifier(CommandLevel.COMPONENT, Command.RESTART);
-    }
-}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/component/ComponentStartJobRunner.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/component/ComponentStartJobRunner.java
deleted file mode 100644
index b0f4c66..0000000
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/component/ComponentStartJobRunner.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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
- *
- *    https://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.bigtop.manager.server.command.job.runner.component;
-
-import org.apache.bigtop.manager.common.enums.Command;
-import org.apache.bigtop.manager.server.command.CommandIdentifier;
-import org.apache.bigtop.manager.server.command.job.runner.AbstractJobRunner;
-import org.apache.bigtop.manager.server.enums.CommandLevel;
-
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Scope;
-
-import lombok.extern.slf4j.Slf4j;
-
-@Slf4j
-@org.springframework.stereotype.Component
-@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class ComponentStartJobRunner extends AbstractJobRunner {
-
-    @Override
-    public CommandIdentifier getCommandIdentifier() {
-        return new CommandIdentifier(CommandLevel.COMPONENT, Command.START);
-    }
-}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/component/ComponentStopJobRunner.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/component/ComponentStopJobRunner.java
deleted file mode 100644
index 7e7c7e4..0000000
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/component/ComponentStopJobRunner.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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
- *
- *    https://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.bigtop.manager.server.command.job.runner.component;
-
-import org.apache.bigtop.manager.common.enums.Command;
-import org.apache.bigtop.manager.server.command.CommandIdentifier;
-import org.apache.bigtop.manager.server.command.job.runner.AbstractJobRunner;
-import org.apache.bigtop.manager.server.enums.CommandLevel;
-
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Scope;
-
-import lombok.extern.slf4j.Slf4j;
-
-@Slf4j
-@org.springframework.stereotype.Component
-@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class ComponentStopJobRunner extends AbstractJobRunner {
-
-    @Override
-    public CommandIdentifier getCommandIdentifier() {
-        return new CommandIdentifier(CommandLevel.COMPONENT, Command.STOP);
-    }
-}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/service/ServiceConfigureJobRunner.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/service/ServiceConfigureJobRunner.java
deleted file mode 100644
index 0998b36..0000000
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/service/ServiceConfigureJobRunner.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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
- *
- *    https://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.bigtop.manager.server.command.job.runner.service;
-
-import org.apache.bigtop.manager.common.enums.Command;
-import org.apache.bigtop.manager.server.command.CommandIdentifier;
-import org.apache.bigtop.manager.server.command.job.runner.AbstractJobRunner;
-import org.apache.bigtop.manager.server.enums.CommandLevel;
-
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Scope;
-
-import lombok.extern.slf4j.Slf4j;
-
-@Slf4j
-@org.springframework.stereotype.Component
-@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class ServiceConfigureJobRunner extends AbstractJobRunner {
-
-    @Override
-    public CommandIdentifier getCommandIdentifier() {
-        return new CommandIdentifier(CommandLevel.SERVICE, Command.CONFIGURE);
-    }
-}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/service/ServiceRestartJobRunner.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/service/ServiceRestartJobRunner.java
deleted file mode 100644
index 1c1d0d4..0000000
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/service/ServiceRestartJobRunner.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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
- *
- *    https://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.bigtop.manager.server.command.job.runner.service;
-
-import org.apache.bigtop.manager.common.enums.Command;
-import org.apache.bigtop.manager.server.command.CommandIdentifier;
-import org.apache.bigtop.manager.server.command.job.runner.AbstractJobRunner;
-import org.apache.bigtop.manager.server.enums.CommandLevel;
-
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Scope;
-
-import lombok.extern.slf4j.Slf4j;
-
-@Slf4j
-@org.springframework.stereotype.Component
-@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class ServiceRestartJobRunner extends AbstractJobRunner {
-
-    @Override
-    public CommandIdentifier getCommandIdentifier() {
-        return new CommandIdentifier(CommandLevel.SERVICE, Command.RESTART);
-    }
-}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/service/ServiceStartJobRunner.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/service/ServiceStartJobRunner.java
deleted file mode 100644
index 723bdec..0000000
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/service/ServiceStartJobRunner.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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
- *
- *    https://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.bigtop.manager.server.command.job.runner.service;
-
-import org.apache.bigtop.manager.common.enums.Command;
-import org.apache.bigtop.manager.server.command.CommandIdentifier;
-import org.apache.bigtop.manager.server.command.job.runner.AbstractJobRunner;
-import org.apache.bigtop.manager.server.enums.CommandLevel;
-
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Scope;
-
-import lombok.extern.slf4j.Slf4j;
-
-@Slf4j
-@org.springframework.stereotype.Component
-@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class ServiceStartJobRunner extends AbstractJobRunner {
-
-    @Override
-    public CommandIdentifier getCommandIdentifier() {
-        return new CommandIdentifier(CommandLevel.SERVICE, Command.START);
-    }
-}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/service/ServiceStopJobRunner.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/service/ServiceStopJobRunner.java
deleted file mode 100644
index ca69940..0000000
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/runner/service/ServiceStopJobRunner.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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
- *
- *    https://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.bigtop.manager.server.command.job.runner.service;
-
-import org.apache.bigtop.manager.common.enums.Command;
-import org.apache.bigtop.manager.server.command.CommandIdentifier;
-import org.apache.bigtop.manager.server.command.job.runner.AbstractJobRunner;
-import org.apache.bigtop.manager.server.enums.CommandLevel;
-
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Scope;
-
-import lombok.extern.slf4j.Slf4j;
-
-@Slf4j
-@org.springframework.stereotype.Component
-@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class ServiceStopJobRunner extends AbstractJobRunner {
-
-    @Override
-    public CommandIdentifier getCommandIdentifier() {
-        return new CommandIdentifier(CommandLevel.SERVICE, Command.STOP);
-    }
-}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/scheduler/DefaultJobScheduler.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/scheduler/DefaultJobScheduler.java
index 54ce12e..ef7b782 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/scheduler/DefaultJobScheduler.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/scheduler/DefaultJobScheduler.java
@@ -18,9 +18,7 @@
  */
 package org.apache.bigtop.manager.server.command.scheduler;
 
-import org.apache.bigtop.manager.dao.po.JobPO;
-import org.apache.bigtop.manager.server.command.job.runner.JobRunner;
-import org.apache.bigtop.manager.server.command.job.runner.JobRunners;
+import org.apache.bigtop.manager.server.command.job.Job;
 import org.apache.bigtop.manager.server.holder.SessionUserHolder;
 
 import org.springframework.stereotype.Component;
@@ -43,13 +41,12 @@ public class DefaultJobScheduler implements JobScheduler {
     private volatile boolean running = true;
 
     @Override
-    public void submit(JobPO jobPO) {
+    public void submit(Job job) {
         Long userId = SessionUserHolder.getUserId();
         queue.offer(() -> {
             try {
                 SessionUserHolder.setUserId(userId);
-                JobRunner runner = JobRunners.getJobRunner(jobPO);
-                runner.run();
+                job.run();
             } finally {
                 SessionUserHolder.clear();
             }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/scheduler/JobScheduler.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/scheduler/JobScheduler.java
index 4a808e4..c6248ed 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/scheduler/JobScheduler.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/scheduler/JobScheduler.java
@@ -18,7 +18,7 @@
  */
 package org.apache.bigtop.manager.server.command.scheduler;
 
-import org.apache.bigtop.manager.dao.po.JobPO;
+import org.apache.bigtop.manager.server.command.job.Job;
 
 /**
  * JobScheduler interface for job management.
@@ -28,9 +28,9 @@ public interface JobScheduler {
 
     /**
      * Submits a job to the job scheduler.
-     * @param jobPO The job to be submitted.
+     * @param job The job to be submitted.
      */
-    void submit(JobPO jobPO);
+    void submit(Job job);
 
     /**
      * Starts the job scheduler.
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/AbstractComponentStage.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/AbstractComponentStage.java
new file mode 100644
index 0000000..946acf9
--- /dev/null
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/AbstractComponentStage.java
@@ -0,0 +1,87 @@
+/*
+ * 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
+ *
+ *    https://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.bigtop.manager.server.command.stage;
+
+import org.apache.bigtop.manager.dao.po.ClusterPO;
+import org.apache.bigtop.manager.dao.repository.ClusterRepository;
+import org.apache.bigtop.manager.server.command.task.TaskContext;
+import org.apache.bigtop.manager.server.holder.SpringContextHolder;
+import org.apache.bigtop.manager.server.model.dto.ComponentDTO;
+import org.apache.bigtop.manager.server.model.dto.ServiceDTO;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public abstract class AbstractComponentStage extends AbstractStage {
+
+    private ClusterRepository clusterRepository;
+
+    private ClusterPO clusterPO;
+
+    public AbstractComponentStage(StageContext stageContext) {
+        super(stageContext);
+    }
+
+    @Override
+    protected void injectBeans() {
+        super.injectBeans();
+
+        this.clusterRepository = SpringContextHolder.getBean(ClusterRepository.class);
+    }
+
+    @Override
+    protected void beforeCreateTasks() {
+        this.clusterPO = clusterRepository.getReferenceById(stageContext.getClusterId());
+    }
+
+    @Override
+    protected String getServiceName() {
+        return stageContext.getServiceDTO().getServiceName();
+    }
+
+    @Override
+    protected String getComponentName() {
+        return stageContext.getComponentDTO().getComponentName();
+    }
+
+    protected TaskContext createTaskContext(String hostname) {
+        ServiceDTO serviceDTO = stageContext.getServiceDTO();
+        ComponentDTO componentDTO = stageContext.getComponentDTO();
+
+        TaskContext taskContext = new TaskContext();
+        taskContext.setHostname(hostname);
+        taskContext.setClusterId(clusterPO.getId());
+        taskContext.setClusterName(clusterPO.getClusterName());
+        taskContext.setServiceName(serviceDTO.getServiceName());
+        taskContext.setStackName(stageContext.getStackName());
+        taskContext.setStackVersion(stageContext.getStackVersion());
+        taskContext.setComponentName(componentDTO.getComponentName());
+        taskContext.setComponentDisplayName(componentDTO.getDisplayName());
+        taskContext.setServiceUser(serviceDTO.getServiceUser());
+        taskContext.setServiceGroup(serviceDTO.getServiceGroup());
+        taskContext.setRoot(clusterPO.getRoot());
+
+        Map<String, Object> properties = new HashMap<>();
+        properties.put("customCommands", componentDTO.getCustomCommands());
+        properties.put("osSpecifics", serviceDTO.getOsSpecifics());
+        properties.put("commandScript", componentDTO.getCommandScript());
+        taskContext.setProperties(properties);
+        return taskContext;
+    }
+}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/AbstractStage.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/AbstractStage.java
new file mode 100644
index 0000000..4b72b62
--- /dev/null
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/AbstractStage.java
@@ -0,0 +1,150 @@
+/*
+ * 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
+ *
+ *    https://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.bigtop.manager.server.command.stage;
+
+import org.apache.bigtop.manager.common.enums.JobState;
+import org.apache.bigtop.manager.common.utils.JsonUtils;
+import org.apache.bigtop.manager.dao.po.StagePO;
+import org.apache.bigtop.manager.dao.repository.StageRepository;
+import org.apache.bigtop.manager.server.command.task.Task;
+import org.apache.bigtop.manager.server.holder.SpringContextHolder;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+public abstract class AbstractStage implements Stage {
+
+    protected StageRepository stageRepository;
+
+    protected StageContext stageContext;
+    protected List<Task> tasks;
+
+    /**
+     * Do not use this directly, please use {@link #getStagePO()} to make sure it's initialized.
+     */
+    private StagePO stagePO;
+
+    public AbstractStage(StageContext stageContext) {
+        this.stageContext = stageContext;
+        this.tasks = new ArrayList<>();
+
+        injectBeans();
+
+        beforeCreateTasks();
+
+        for (String hostname : stageContext.getHostnames()) {
+            tasks.add(createTask(hostname));
+        }
+    }
+
+    protected void injectBeans() {
+        this.stageRepository = SpringContextHolder.getBean(StageRepository.class);
+    }
+
+    protected abstract void beforeCreateTasks();
+
+    protected abstract Task createTask(String hostname);
+
+    protected String getServiceName() {
+        return "cluster";
+    }
+
+    protected String getComponentName() {
+        return "agent";
+    }
+
+    @Override
+    public void beforeRun() {
+        StagePO stagePO = getStagePO();
+        stagePO.setState(JobState.PROCESSING);
+        stageRepository.save(stagePO);
+    }
+
+    @Override
+    public Boolean run() {
+        beforeRun();
+
+        List<CompletableFuture<Boolean>> futures = new ArrayList<>();
+        for (Task task : tasks) {
+            futures.add(CompletableFuture.supplyAsync(task::run));
+        }
+
+        List<Boolean> taskResults = futures.stream()
+                .map((future) -> {
+                    try {
+                        return future.get();
+                    } catch (Exception e) {
+                        return false;
+                    }
+                })
+                .toList();
+
+        boolean allTaskSuccess = taskResults.stream().allMatch(Boolean::booleanValue);
+        if (allTaskSuccess) {
+            onSuccess();
+        } else {
+            onFailure();
+        }
+
+        return allTaskSuccess;
+    }
+
+    @Override
+    public void onSuccess() {
+        StagePO stagePO = getStagePO();
+        stagePO.setState(JobState.SUCCESSFUL);
+        stageRepository.save(stagePO);
+    }
+
+    @Override
+    public void onFailure() {
+        StagePO stagePO = getStagePO();
+        stagePO.setState(JobState.FAILED);
+        stageRepository.save(stagePO);
+    }
+
+    @Override
+    public StageContext getStageContext() {
+        return stageContext;
+    }
+
+    @Override
+    public List<Task> getTasks() {
+        return tasks;
+    }
+
+    @Override
+    public void loadStagePO(StagePO stagePO) {
+        this.stagePO = stagePO;
+    }
+
+    @Override
+    public StagePO getStagePO() {
+        if (stagePO == null) {
+            stagePO = new StagePO();
+            stagePO.setName(getName());
+            stagePO.setServiceName(getServiceName());
+            stagePO.setComponentName(getComponentName());
+            stagePO.setContext(JsonUtils.writeAsString(stageContext));
+        }
+
+        return stagePO;
+    }
+}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/CacheFileUpdateStage.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/CacheFileUpdateStage.java
new file mode 100644
index 0000000..960b25f
--- /dev/null
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/CacheFileUpdateStage.java
@@ -0,0 +1,93 @@
+/*
+ * 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
+ *
+ *    https://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.bigtop.manager.server.command.stage;
+
+import org.apache.bigtop.manager.common.enums.Command;
+import org.apache.bigtop.manager.dao.po.HostPO;
+import org.apache.bigtop.manager.dao.repository.HostRepository;
+import org.apache.bigtop.manager.server.command.task.CacheFileUpdateTask;
+import org.apache.bigtop.manager.server.command.task.Task;
+import org.apache.bigtop.manager.server.command.task.TaskContext;
+import org.apache.bigtop.manager.server.holder.SpringContextHolder;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class CacheFileUpdateStage extends AbstractStage {
+
+    private HostRepository hostRepository;
+
+    public CacheFileUpdateStage(StageContext stageContext) {
+        super(stageContext);
+    }
+
+    @Override
+    protected void injectBeans() {
+        super.injectBeans();
+
+        this.hostRepository = SpringContextHolder.getBean(HostRepository.class);
+    }
+
+    @Override
+    protected void beforeCreateTasks() {
+        List<String> hostnames = new ArrayList<>();
+
+        if (stageContext.getClusterId() == null) {
+            hostnames.addAll(stageContext.getHostnames());
+        } else {
+            hostnames.addAll(stageContext.getHostnames() == null ? List.of() : stageContext.getHostnames());
+            hostnames.addAll(hostRepository.findAllByClusterPOId(stageContext.getClusterId()).stream()
+                    .map(HostPO::getHostname)
+                    .toList());
+        }
+
+        stageContext.setHostnames(hostnames);
+    }
+
+    @Override
+    protected Task createTask(String hostname) {
+        TaskContext taskContext = new TaskContext();
+        taskContext.setHostname(hostname);
+        taskContext.setClusterId(stageContext.getClusterId());
+        taskContext.setClusterName(stageContext.getClusterName());
+        taskContext.setStackName(stageContext.getStackName());
+        taskContext.setStackVersion(stageContext.getStackVersion());
+        taskContext.setServiceName("cluster");
+        taskContext.setServiceUser("root");
+        taskContext.setServiceGroup("root");
+        taskContext.setComponentName("agent");
+        taskContext.setComponentDisplayName("Agent");
+        taskContext.setCommand(Command.CUSTOM);
+        taskContext.setCustomCommand("update_cache_files");
+
+        Map<String, Object> properties = new HashMap<>();
+        properties.put("repoInfoList", stageContext.getRepoInfoList());
+        properties.put("hostnames", stageContext.getHostnames());
+        taskContext.setProperties(properties);
+
+        return new CacheFileUpdateTask(taskContext);
+    }
+
+    @Override
+    public String getName() {
+        return "Update cache files";
+    }
+}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/StageType.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/ComponentCheckStage.java
similarity index 57%
copy from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/StageType.java
copy to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/ComponentCheckStage.java
index dc12b71..7498ce7 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/StageType.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/ComponentCheckStage.java
@@ -16,23 +16,24 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.stage.factory;
+package org.apache.bigtop.manager.server.command.stage;
 
-public enum StageType {
-    HOST_CHECK,
+import org.apache.bigtop.manager.server.command.task.ComponentCheckTask;
+import org.apache.bigtop.manager.server.command.task.Task;
 
-    CACHE_DISTRIBUTE,
+public class ComponentCheckStage extends AbstractComponentStage {
 
-    COMPONENT_INSTALL,
+    public ComponentCheckStage(StageContext stageContext) {
+        super(stageContext);
+    }
 
-    COMPONENT_START,
+    @Override
+    protected Task createTask(String hostname) {
+        return new ComponentCheckTask(createTaskContext(hostname));
+    }
 
-    COMPONENT_STOP,
-
-    COMPONENT_CHECK,
-
-    SERVICE_CHECK,
-
-    SERVICE_CONFIGURE,
-    ;
+    @Override
+    public String getName() {
+        return "Check " + stageContext.getComponentDTO().getDisplayName();
+    }
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/runner/host/HostCheckStageRunner.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/ComponentInstallStage.java
similarity index 57%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/runner/host/HostCheckStageRunner.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/ComponentInstallStage.java
index eed2807..57fe9c7 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/runner/host/HostCheckStageRunner.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/ComponentInstallStage.java
@@ -16,22 +16,24 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.stage.runner.host;
+package org.apache.bigtop.manager.server.command.stage;
 
-import org.apache.bigtop.manager.server.command.stage.factory.StageType;
-import org.apache.bigtop.manager.server.command.stage.runner.AbstractStageRunner;
+import org.apache.bigtop.manager.server.command.task.ComponentInstallTask;
+import org.apache.bigtop.manager.server.command.task.Task;
 
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Scope;
+public class ComponentInstallStage extends AbstractComponentStage {
 
-import lombok.extern.slf4j.Slf4j;
+    public ComponentInstallStage(StageContext stageContext) {
+        super(stageContext);
+    }
 
-@Slf4j
-@org.springframework.stereotype.Component
-@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class HostCheckStageRunner extends AbstractStageRunner {
+    @Override
+    protected Task createTask(String hostname) {
+        return new ComponentInstallTask(createTaskContext(hostname));
+    }
 
-    public StageType getStageType() {
-        return StageType.HOST_CHECK;
+    @Override
+    public String getName() {
+        return "Install " + stageContext.getComponentDTO().getDisplayName();
     }
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/StageType.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/ComponentStartStage.java
similarity index 57%
copy from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/StageType.java
copy to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/ComponentStartStage.java
index dc12b71..00f67f8 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/StageType.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/ComponentStartStage.java
@@ -16,23 +16,24 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.stage.factory;
+package org.apache.bigtop.manager.server.command.stage;
 
-public enum StageType {
-    HOST_CHECK,
+import org.apache.bigtop.manager.server.command.task.ComponentStartTask;
+import org.apache.bigtop.manager.server.command.task.Task;
 
-    CACHE_DISTRIBUTE,
+public class ComponentStartStage extends AbstractComponentStage {
 
-    COMPONENT_INSTALL,
+    public ComponentStartStage(StageContext stageContext) {
+        super(stageContext);
+    }
 
-    COMPONENT_START,
+    @Override
+    protected Task createTask(String hostname) {
+        return new ComponentStartTask(createTaskContext(hostname));
+    }
 
-    COMPONENT_STOP,
-
-    COMPONENT_CHECK,
-
-    SERVICE_CHECK,
-
-    SERVICE_CONFIGURE,
-    ;
+    @Override
+    public String getName() {
+        return "Start " + stageContext.getComponentDTO().getDisplayName();
+    }
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/StageType.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/ComponentStopStage.java
similarity index 57%
copy from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/StageType.java
copy to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/ComponentStopStage.java
index dc12b71..b367815 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/StageType.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/ComponentStopStage.java
@@ -16,23 +16,24 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.stage.factory;
+package org.apache.bigtop.manager.server.command.stage;
 
-public enum StageType {
-    HOST_CHECK,
+import org.apache.bigtop.manager.server.command.task.ComponentStopTask;
+import org.apache.bigtop.manager.server.command.task.Task;
 
-    CACHE_DISTRIBUTE,
+public class ComponentStopStage extends AbstractComponentStage {
 
-    COMPONENT_INSTALL,
+    public ComponentStopStage(StageContext stageContext) {
+        super(stageContext);
+    }
 
-    COMPONENT_START,
+    @Override
+    protected Task createTask(String hostname) {
+        return new ComponentStopTask(createTaskContext(hostname));
+    }
 
-    COMPONENT_STOP,
-
-    COMPONENT_CHECK,
-
-    SERVICE_CHECK,
-
-    SERVICE_CONFIGURE,
-    ;
+    @Override
+    public String getName() {
+        return "Stop " + stageContext.getComponentDTO().getDisplayName();
+    }
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/HostCheckStage.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/HostCheckStage.java
new file mode 100644
index 0000000..eea7846
--- /dev/null
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/HostCheckStage.java
@@ -0,0 +1,77 @@
+/*
+ * 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
+ *
+ *    https://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.bigtop.manager.server.command.stage;
+
+import org.apache.bigtop.manager.common.enums.Command;
+import org.apache.bigtop.manager.dao.po.ClusterPO;
+import org.apache.bigtop.manager.dao.repository.ClusterRepository;
+import org.apache.bigtop.manager.server.command.task.HostCheckTask;
+import org.apache.bigtop.manager.server.command.task.Task;
+import org.apache.bigtop.manager.server.command.task.TaskContext;
+import org.apache.bigtop.manager.server.holder.SpringContextHolder;
+
+public class HostCheckStage extends AbstractStage {
+
+    private ClusterRepository clusterRepository;
+
+    public HostCheckStage(StageContext stageContext) {
+        super(stageContext);
+    }
+
+    @Override
+    protected void injectBeans() {
+        super.injectBeans();
+
+        this.clusterRepository = SpringContextHolder.getBean(ClusterRepository.class);
+    }
+
+    @Override
+    protected void beforeCreateTasks() {
+        if (stageContext.getClusterId() != null) {
+            ClusterPO clusterPO = clusterRepository.getReferenceById(stageContext.getClusterId());
+
+            stageContext.setStackName(clusterPO.getStackPO().getStackName());
+            stageContext.setStackVersion(clusterPO.getStackPO().getStackVersion());
+        }
+    }
+
+    @Override
+    protected Task createTask(String hostname) {
+        TaskContext taskContext = new TaskContext();
+        taskContext.setHostname(hostname);
+        taskContext.setClusterId(stageContext.getClusterId());
+        taskContext.setClusterName(stageContext.getClusterName());
+        taskContext.setStackName(stageContext.getStackName());
+        taskContext.setStackVersion(stageContext.getStackVersion());
+        taskContext.setServiceName("cluster");
+        taskContext.setServiceUser("root");
+        taskContext.setServiceGroup("root");
+        taskContext.setComponentName("agent");
+        taskContext.setComponentDisplayName("Agent");
+        taskContext.setCommand(Command.CUSTOM);
+        taskContext.setCustomCommand("check_host");
+
+        return new HostCheckTask(taskContext);
+    }
+
+    @Override
+    public String getName() {
+        return "Check hosts";
+    }
+}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/StageFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/Stage.java
similarity index 68%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/StageFactory.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/Stage.java
index 1d4398e..91f55b8 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/StageFactory.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/Stage.java
@@ -16,27 +16,30 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.stage.factory;
+package org.apache.bigtop.manager.server.command.stage;
 
 import org.apache.bigtop.manager.dao.po.StagePO;
+import org.apache.bigtop.manager.server.command.task.Task;
 
-/**
- * Stage factory.
- */
-public interface StageFactory {
-
-    /**
-     * Gets the type of the stage.
-     *
-     * @return the type of the stage
-     */
-    StageType getStageType();
-
-    /**
-     * Creates a stage.
-     *
-     * @param context the stage context
-     * @return the stage
-     */
-    StagePO createStage(StageContext context);
+import java.util.List;
+
+public interface Stage {
+
+    String getName();
+
+    void beforeRun();
+
+    Boolean run();
+
+    void onSuccess();
+
+    void onFailure();
+
+    StageContext getStageContext();
+
+    List<Task> getTasks();
+
+    void loadStagePO(StagePO stagePO);
+
+    StagePO getStagePO();
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/StageContext.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/StageContext.java
similarity index 95%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/StageContext.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/StageContext.java
index 86240e2..dd26a7d 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/StageContext.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/StageContext.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.stage.factory;
+package org.apache.bigtop.manager.server.command.stage;
 
 import org.apache.bigtop.manager.common.utils.JsonUtils;
 import org.apache.bigtop.manager.server.model.dto.CommandDTO;
@@ -33,8 +33,6 @@ import java.util.List;
 @Data
 public class StageContext {
 
-    private StageType stageType;
-
     private Long clusterId;
 
     private String clusterName;
@@ -52,9 +50,12 @@ public class StageContext {
     private List<RepoDTO> repoInfoList;
 
     public static StageContext fromPayload(String payload) {
-        StageContext context = new StageContext();
         CommandDTO commandDTO = JsonUtils.readFromString(payload, CommandDTO.class);
+        return fromCommandDTO(commandDTO);
+    }
 
+    public static StageContext fromCommandDTO(CommandDTO commandDTO) {
+        StageContext context = new StageContext();
         context.setClusterId(commandDTO.getClusterId());
 
         switch (commandDTO.getCommandLevel()) {
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/AbstractStageFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/AbstractStageFactory.java
deleted file mode 100644
index b272e10..0000000
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/AbstractStageFactory.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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
- *
- *    https://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.bigtop.manager.server.command.stage.factory;
-
-import org.apache.bigtop.manager.common.utils.JsonUtils;
-import org.apache.bigtop.manager.dao.po.StagePO;
-
-public abstract class AbstractStageFactory implements StageFactory {
-
-    protected StageContext context;
-
-    protected StagePO stagePO;
-
-    @Override
-    public StagePO createStage(StageContext context) {
-        this.context = context;
-        this.context.setStageType(getStageType());
-
-        this.stagePO = new StagePO();
-        this.stagePO.setContext(JsonUtils.writeAsString(context));
-
-        doCreateStage();
-
-        return this.stagePO;
-    }
-
-    protected abstract void doCreateStage();
-}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/StageFactories.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/StageFactories.java
deleted file mode 100644
index 1460316..0000000
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/StageFactories.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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
- *
- *    https://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.bigtop.manager.server.command.stage.factory;
-
-import org.apache.bigtop.manager.server.holder.SpringContextHolder;
-
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-@Slf4j
-public class StageFactories {
-
-    private static final AtomicBoolean LOADED = new AtomicBoolean(false);
-
-    private static final Map<StageType, String> STAGE_FACTORIES = new HashMap<>();
-
-    public static StageFactory getStageFactory(StageType stageType) {
-        if (!LOADED.get()) {
-            load();
-        }
-
-        String beanName = STAGE_FACTORIES.get(stageType);
-        return SpringContextHolder.getApplicationContext().getBean(beanName, StageFactory.class);
-    }
-
-    private static synchronized void load() {
-        if (LOADED.get()) {
-            return;
-        }
-
-        for (Map.Entry<String, StageFactory> entry :
-                SpringContextHolder.getStageFactories().entrySet()) {
-            String beanName = entry.getKey();
-            StageFactory stageFactory = entry.getValue();
-            if (STAGE_FACTORIES.containsKey(stageFactory.getStageType())) {
-                log.error("Duplicate StageLifecycle with type: {}", stageFactory.getStageType());
-                continue;
-            }
-
-            STAGE_FACTORIES.put(stageFactory.getStageType(), beanName);
-            log.info(
-                    "Load StageLifecycle: {} with type: {}",
-                    stageFactory.getClass().getName(),
-                    stageFactory.getStageType());
-        }
-
-        LOADED.set(true);
-    }
-}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/component/ComponentInstallStageFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/component/ComponentInstallStageFactory.java
deleted file mode 100644
index 1e9eaba..0000000
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/component/ComponentInstallStageFactory.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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
- *
- *    https://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.bigtop.manager.server.command.stage.factory.component;
-
-import org.apache.bigtop.manager.common.enums.Command;
-import org.apache.bigtop.manager.server.command.stage.factory.StageType;
-
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Scope;
-
-import lombok.extern.slf4j.Slf4j;
-
-@Slf4j
-@org.springframework.stereotype.Component
-@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class ComponentInstallStageFactory extends AbstractComponentStageFactory {
-
-    @Override
-    public StageType getStageType() {
-        return StageType.COMPONENT_INSTALL;
-    }
-
-    @Override
-    protected Command getCommand() {
-        return Command.INSTALL;
-    }
-}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/component/ComponentStartStageFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/component/ComponentStartStageFactory.java
deleted file mode 100644
index 7604c75..0000000
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/component/ComponentStartStageFactory.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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
- *
- *    https://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.bigtop.manager.server.command.stage.factory.component;
-
-import org.apache.bigtop.manager.common.enums.Command;
-import org.apache.bigtop.manager.server.command.stage.factory.StageType;
-
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Scope;
-
-import lombok.extern.slf4j.Slf4j;
-
-@Slf4j
-@org.springframework.stereotype.Component
-@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class ComponentStartStageFactory extends AbstractComponentStageFactory {
-
-    @Override
-    public StageType getStageType() {
-        return StageType.COMPONENT_START;
-    }
-
-    @Override
-    protected Command getCommand() {
-        return Command.START;
-    }
-}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/config/CacheDistributeStageFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/config/CacheDistributeStageFactory.java
deleted file mode 100644
index c29066a..0000000
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/config/CacheDistributeStageFactory.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * 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
- *
- *    https://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.bigtop.manager.server.command.stage.factory.config;
-
-import org.apache.bigtop.manager.common.enums.Command;
-import org.apache.bigtop.manager.dao.po.HostPO;
-import org.apache.bigtop.manager.dao.po.TaskPO;
-import org.apache.bigtop.manager.dao.repository.HostRepository;
-import org.apache.bigtop.manager.server.command.stage.factory.AbstractStageFactory;
-import org.apache.bigtop.manager.server.command.stage.factory.StageType;
-
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Scope;
-
-import lombok.extern.slf4j.Slf4j;
-
-import jakarta.annotation.Resource;
-import java.util.ArrayList;
-import java.util.List;
-
-@Slf4j
-@org.springframework.stereotype.Component
-@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class CacheDistributeStageFactory extends AbstractStageFactory {
-
-    @Resource
-    private HostRepository hostRepository;
-
-    @Override
-    public StageType getStageType() {
-        return StageType.CACHE_DISTRIBUTE;
-    }
-
-    @Override
-    public void doCreateStage() {
-        List<String> hostnames = new ArrayList<>();
-        if (context.getClusterId() == null) {
-            hostnames.addAll(context.getHostnames());
-        } else {
-            hostnames.addAll(context.getHostnames() == null ? List.of() : context.getHostnames());
-            hostnames.addAll(hostRepository.findAllByClusterPOId(context.getClusterId()).stream()
-                    .map(HostPO::getHostname)
-                    .toList());
-        }
-
-        stagePO.setName("Distribute Caches");
-
-        List<TaskPO> taskPOList = new ArrayList<>();
-        hostnames = hostnames.stream().distinct().toList();
-        for (String hostname : hostnames) {
-            TaskPO taskPO = new TaskPO();
-            taskPO.setName(stagePO.getName() + " on " + hostname);
-            taskPO.setStackName(context.getStackName());
-            taskPO.setStackVersion(context.getStackVersion());
-            taskPO.setHostname(hostname);
-            taskPO.setServiceName("cluster");
-            taskPO.setServiceUser("root");
-            taskPO.setServiceGroup("root");
-            taskPO.setComponentName("bigtop-manager-agent");
-            taskPO.setCommand(Command.CUSTOM);
-            taskPO.setCustomCommand("cache_host");
-            taskPOList.add(taskPO);
-        }
-
-        stagePO.setTaskPOList(taskPOList);
-    }
-}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/host/HostCheckStageFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/host/HostCheckStageFactory.java
deleted file mode 100644
index e92b2b9..0000000
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/host/HostCheckStageFactory.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * 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
- *
- *    https://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.bigtop.manager.server.command.stage.factory.host;
-
-import org.apache.bigtop.manager.common.enums.Command;
-import org.apache.bigtop.manager.common.message.entity.payload.HostCheckPayload;
-import org.apache.bigtop.manager.common.utils.JsonUtils;
-import org.apache.bigtop.manager.dao.po.ClusterPO;
-import org.apache.bigtop.manager.dao.po.TaskPO;
-import org.apache.bigtop.manager.dao.repository.ClusterRepository;
-import org.apache.bigtop.manager.grpc.generated.CommandRequest;
-import org.apache.bigtop.manager.grpc.generated.CommandType;
-import org.apache.bigtop.manager.grpc.utils.ProtobufUtil;
-import org.apache.bigtop.manager.server.command.stage.factory.AbstractStageFactory;
-import org.apache.bigtop.manager.server.command.stage.factory.StageType;
-
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Scope;
-
-import lombok.extern.slf4j.Slf4j;
-
-import jakarta.annotation.Resource;
-import java.util.ArrayList;
-import java.util.List;
-
-@Slf4j
-@org.springframework.stereotype.Component
-@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class HostCheckStageFactory extends AbstractStageFactory {
-
-    @Resource
-    private ClusterRepository clusterRepository;
-
-    public StageType getStageType() {
-        return StageType.HOST_CHECK;
-    }
-
-    @Override
-    public void doCreateStage() {
-        if (context.getClusterId() != null) {
-            ClusterPO clusterPO = clusterRepository.getReferenceById(context.getClusterId());
-
-            context.setStackName(clusterPO.getStackPO().getStackName());
-            context.setStackVersion(clusterPO.getStackPO().getStackVersion());
-        }
-
-        // Create stages
-        stagePO.setName("Check Hosts");
-
-        List<TaskPO> taskPOList = new ArrayList<>();
-        for (String hostname : context.getHostnames()) {
-            TaskPO taskPO = new TaskPO();
-            taskPO.setName(stagePO.getName() + " on " + hostname);
-            taskPO.setStackName(context.getStackName());
-            taskPO.setStackVersion(context.getStackVersion());
-            taskPO.setHostname(hostname);
-            taskPO.setServiceName("cluster");
-            taskPO.setServiceUser("root");
-            taskPO.setServiceGroup("root");
-            taskPO.setComponentName("bigtop-manager-agent");
-            taskPO.setCommand(Command.CUSTOM);
-            taskPO.setCustomCommand("check_host");
-
-            CommandRequest request = createMessage(hostname);
-            taskPO.setContent(ProtobufUtil.toJson(request));
-
-            taskPOList.add(taskPO);
-        }
-
-        stagePO.setTaskPOList(taskPOList);
-    }
-
-    private CommandRequest createMessage(String hostname) {
-        HostCheckPayload messagePayload = new HostCheckPayload();
-        messagePayload.setHostname(hostname);
-
-        CommandRequest.Builder builder = CommandRequest.newBuilder();
-        builder.setType(CommandType.HOST_CHECK);
-        builder.setHostname(hostname);
-        builder.setPayload(JsonUtils.writeAsString(messagePayload));
-
-        return builder.build();
-    }
-}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/service/ServiceConfigureStageFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/service/ServiceConfigureStageFactory.java
deleted file mode 100644
index 1da995c..0000000
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/service/ServiceConfigureStageFactory.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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
- *
- *    https://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.bigtop.manager.server.command.stage.factory.service;
-
-import org.apache.bigtop.manager.server.command.stage.factory.AbstractStageFactory;
-import org.apache.bigtop.manager.server.command.stage.factory.StageType;
-
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Scope;
-
-import lombok.extern.slf4j.Slf4j;
-
-@Slf4j
-@org.springframework.stereotype.Component
-@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class ServiceConfigureStageFactory extends AbstractStageFactory {
-
-    @Override
-    public StageType getStageType() {
-        return StageType.SERVICE_CONFIGURE;
-    }
-
-    @Override
-    public void doCreateStage() {}
-}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/runner/AbstractStageRunner.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/runner/AbstractStageRunner.java
deleted file mode 100644
index 59b4650..0000000
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/runner/AbstractStageRunner.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * 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
- *
- *    https://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.bigtop.manager.server.command.stage.runner;
-
-import org.apache.bigtop.manager.common.constants.MessageConstants;
-import org.apache.bigtop.manager.common.enums.JobState;
-import org.apache.bigtop.manager.dao.po.StagePO;
-import org.apache.bigtop.manager.dao.po.TaskPO;
-import org.apache.bigtop.manager.dao.repository.StageRepository;
-import org.apache.bigtop.manager.dao.repository.TaskRepository;
-import org.apache.bigtop.manager.grpc.generated.CommandReply;
-import org.apache.bigtop.manager.grpc.generated.CommandRequest;
-import org.apache.bigtop.manager.grpc.generated.CommandServiceGrpc;
-import org.apache.bigtop.manager.grpc.utils.ProtobufUtil;
-import org.apache.bigtop.manager.server.command.stage.factory.StageContext;
-import org.apache.bigtop.manager.server.grpc.GrpcClient;
-
-import lombok.extern.slf4j.Slf4j;
-
-import jakarta.annotation.Resource;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.CompletableFuture;
-
-@Slf4j
-public abstract class AbstractStageRunner implements StageRunner {
-
-    @Resource
-    protected StageRepository stageRepository;
-
-    @Resource
-    protected TaskRepository taskRepository;
-
-    protected StagePO stagePO;
-
-    protected StageContext stageContext;
-
-    @Override
-    public void setStage(StagePO stagePO) {
-        this.stagePO = stagePO;
-    }
-
-    @Override
-    public void setStageContext(StageContext stageContext) {
-        this.stageContext = stageContext;
-    }
-
-    @Override
-    public void run() {
-        beforeRun();
-
-        List<CompletableFuture<Boolean>> futures = new ArrayList<>();
-        for (TaskPO taskPO : stagePO.getTaskPOList()) {
-            beforeRunTask(taskPO);
-
-            CommandRequest protoRequest = ProtobufUtil.fromJson(taskPO.getContent(), CommandRequest.class);
-            CommandRequest.Builder builder = CommandRequest.newBuilder(protoRequest);
-            builder.setTaskId(taskPO.getId());
-            builder.setStageId(stagePO.getId());
-            builder.setJobId(stagePO.getJobPO().getId());
-            CommandRequest request = builder.build();
-
-            futures.add(CompletableFuture.supplyAsync(() -> {
-                CommandServiceGrpc.CommandServiceBlockingStub stub = GrpcClient.getBlockingStub(
-                        taskPO.getHostname(), CommandServiceGrpc.CommandServiceBlockingStub.class);
-                CommandReply reply = stub.exec(request);
-
-                log.info("Execute task {} completed: {}", taskPO.getId(), reply);
-                boolean taskSuccess = reply != null && reply.getCode() == MessageConstants.SUCCESS_CODE;
-
-                if (taskSuccess) {
-                    onTaskSuccess(taskPO);
-                } else {
-                    onTaskFailure(taskPO);
-                }
-
-                return taskSuccess;
-            }));
-        }
-
-        List<Boolean> taskResults = futures.stream()
-                .map((future) -> {
-                    try {
-                        return future.get();
-                    } catch (Exception e) {
-                        log.error("Error running task", e);
-                        return false;
-                    }
-                })
-                .toList();
-
-        boolean allTaskSuccess = taskResults.stream().allMatch(Boolean::booleanValue);
-        if (allTaskSuccess) {
-            onSuccess();
-        } else {
-            onFailure();
-        }
-    }
-
-    @Override
-    public void beforeRun() {
-        stagePO.setState(JobState.PROCESSING);
-        stageRepository.save(stagePO);
-    }
-
-    @Override
-    public void onSuccess() {
-        stagePO.setState(JobState.SUCCESSFUL);
-        stageRepository.save(stagePO);
-    }
-
-    @Override
-    public void onFailure() {
-        stagePO.setState(JobState.FAILED);
-        stageRepository.save(stagePO);
-    }
-
-    @Override
-    public void beforeRunTask(TaskPO taskPO) {
-        taskPO.setState(JobState.PROCESSING);
-        taskRepository.save(taskPO);
-    }
-
-    @Override
-    public void onTaskSuccess(TaskPO taskPO) {
-        taskPO.setState(JobState.SUCCESSFUL);
-        taskRepository.save(taskPO);
-    }
-
-    @Override
-    public void onTaskFailure(TaskPO taskPO) {
-        taskPO.setState(JobState.FAILED);
-        taskRepository.save(taskPO);
-    }
-}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/runner/StageRunner.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/runner/StageRunner.java
deleted file mode 100644
index 8479039..0000000
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/runner/StageRunner.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * 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
- *
- *    https://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.bigtop.manager.server.command.stage.runner;
-
-import org.apache.bigtop.manager.dao.po.StagePO;
-import org.apache.bigtop.manager.dao.po.TaskPO;
-import org.apache.bigtop.manager.server.command.stage.factory.StageContext;
-import org.apache.bigtop.manager.server.command.stage.factory.StageType;
-
-/**
- * Interface for running stages.
- * A stage represents a phase in a job, and this interface provides methods for managing and running these stages.
- */
-public interface StageRunner {
-
-    /**
-     * Get the type of the stage that this runner is responsible for.
-     *
-     * @return The type of the stage.
-     */
-    StageType getStageType();
-
-    /**
-     * Set the stage that this runner will manage.
-     *
-     * @param stagePO The stage to be managed by this runner.
-     */
-    void setStage(StagePO stagePO);
-
-    /**
-     * Set the context for the stage. The context may contain additional information necessary for running the stage.
-     *
-     * @param stageContext The context for the stage.
-     */
-    void setStageContext(StageContext stageContext);
-
-    /**
-     * Method to be called before running the stage. Can be used for setup and preparation.
-     */
-    void beforeRun();
-
-    /**
-     * Run the stage. This is where the main logic of the stage should be implemented.
-     */
-    void run();
-
-    /**
-     * Method to be called after the stage has successfully run. Can be used for cleanup and finalization.
-     */
-    void onSuccess();
-
-    /**
-     * Method to be called if the stage fails to run. Can be used for error handling and recovery.
-     */
-    void onFailure();
-
-    /**
-     * Method to be called before running a task in the stage. Can be used for task-specific setup and preparation.
-     *
-     * @param taskPO The task that is about to be run.
-     */
-    void beforeRunTask(TaskPO taskPO);
-
-    /**
-     * Method to be called after a task in the stage has successfully run. Can be used for task-specific cleanup and finalization.
-     *
-     * @param taskPO The task that has been successfully run.
-     */
-    void onTaskSuccess(TaskPO taskPO);
-
-    /**
-     * Method to be called if a task in the stage fails to run. Can be used for task-specific error handling and recovery.
-     *
-     * @param taskPO The task that has failed to run.
-     */
-    void onTaskFailure(TaskPO taskPO);
-}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/runner/StageRunners.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/runner/StageRunners.java
deleted file mode 100644
index add659d..0000000
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/runner/StageRunners.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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
- *
- *    https://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.bigtop.manager.server.command.stage.runner;
-
-import org.apache.bigtop.manager.common.utils.JsonUtils;
-import org.apache.bigtop.manager.dao.po.StagePO;
-import org.apache.bigtop.manager.server.command.stage.factory.StageContext;
-import org.apache.bigtop.manager.server.command.stage.factory.StageType;
-import org.apache.bigtop.manager.server.holder.SpringContextHolder;
-
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-@Slf4j
-public class StageRunners {
-
-    private static final AtomicBoolean LOADED = new AtomicBoolean(false);
-
-    private static final Map<StageType, String> STAGE_RUNNERS = new HashMap<>();
-
-    public static StageRunner getStageRunner(StagePO stagePO) {
-        if (!LOADED.get()) {
-            load();
-        }
-
-        StageContext stageContext = JsonUtils.readFromString(stagePO.getContext(), StageContext.class);
-        StageType stageType = stageContext.getStageType();
-
-        String beanName = STAGE_RUNNERS.get(stageType);
-        StageRunner runner = SpringContextHolder.getApplicationContext().getBean(beanName, StageRunner.class);
-        runner.setStage(stagePO);
-        runner.setStageContext(stageContext);
-
-        return runner;
-    }
-
-    private static synchronized void load() {
-        if (LOADED.get()) {
-            return;
-        }
-
-        for (Map.Entry<String, StageRunner> entry :
-                SpringContextHolder.getStageRunners().entrySet()) {
-            String beanName = entry.getKey();
-            StageRunner stageRunner = entry.getValue();
-            if (STAGE_RUNNERS.containsKey(stageRunner.getStageType())) {
-                log.error("Duplicate StageLifecycle with type: {}", stageRunner.getStageType());
-                continue;
-            }
-
-            STAGE_RUNNERS.put(stageRunner.getStageType(), beanName);
-            log.info(
-                    "Load StageLifecycle: {} with type: {}",
-                    stageRunner.getClass().getName(),
-                    stageRunner.getStageType());
-        }
-
-        LOADED.set(true);
-    }
-}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/runner/component/ComponentCheckStageRunner.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/runner/component/ComponentCheckStageRunner.java
deleted file mode 100644
index 91db2b6..0000000
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/runner/component/ComponentCheckStageRunner.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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
- *
- *    https://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.bigtop.manager.server.command.stage.runner.component;
-
-import org.apache.bigtop.manager.server.command.stage.factory.StageType;
-import org.apache.bigtop.manager.server.command.stage.runner.AbstractStageRunner;
-
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Scope;
-
-import lombok.extern.slf4j.Slf4j;
-
-@Slf4j
-@org.springframework.stereotype.Component
-@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class ComponentCheckStageRunner extends AbstractStageRunner {
-
-    @Override
-    public StageType getStageType() {
-        return StageType.COMPONENT_CHECK;
-    }
-}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/runner/service/ServiceConfigureStageRunner.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/runner/service/ServiceConfigureStageRunner.java
deleted file mode 100644
index 45bcc65..0000000
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/runner/service/ServiceConfigureStageRunner.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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
- *
- *    https://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.bigtop.manager.server.command.stage.runner.service;
-
-import org.apache.bigtop.manager.server.command.stage.factory.StageType;
-import org.apache.bigtop.manager.server.command.stage.runner.AbstractStageRunner;
-
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Scope;
-
-import lombok.extern.slf4j.Slf4j;
-
-@Slf4j
-@org.springframework.stereotype.Component
-@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class ServiceConfigureStageRunner extends AbstractStageRunner {
-
-    @Override
-    public StageType getStageType() {
-        return StageType.SERVICE_CONFIGURE;
-    }
-}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/component/AbstractComponentStageFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/AbstractComponentTask.java
similarity index 50%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/component/AbstractComponentStageFactory.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/AbstractComponentTask.java
index c6b8136..7160dd7 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/component/AbstractComponentStageFactory.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/AbstractComponentTask.java
@@ -16,99 +16,64 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.stage.factory.component;
+package org.apache.bigtop.manager.server.command.task;
 
-import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.common.message.entity.payload.CommandPayload;
 import org.apache.bigtop.manager.common.message.entity.pojo.CustomCommandInfo;
 import org.apache.bigtop.manager.common.message.entity.pojo.OSSpecificInfo;
 import org.apache.bigtop.manager.common.message.entity.pojo.ScriptInfo;
 import org.apache.bigtop.manager.common.utils.JsonUtils;
-import org.apache.bigtop.manager.dao.po.ClusterPO;
-import org.apache.bigtop.manager.dao.po.TaskPO;
-import org.apache.bigtop.manager.dao.repository.ClusterRepository;
+import org.apache.bigtop.manager.dao.repository.HostComponentRepository;
 import org.apache.bigtop.manager.grpc.generated.CommandRequest;
 import org.apache.bigtop.manager.grpc.generated.CommandType;
-import org.apache.bigtop.manager.grpc.utils.ProtobufUtil;
-import org.apache.bigtop.manager.server.command.stage.factory.AbstractStageFactory;
-import org.apache.bigtop.manager.server.model.dto.ComponentDTO;
+import org.apache.bigtop.manager.server.holder.SpringContextHolder;
 import org.apache.bigtop.manager.server.model.dto.CustomCommandDTO;
 import org.apache.bigtop.manager.server.model.dto.OSSpecificDTO;
 import org.apache.bigtop.manager.server.model.dto.ScriptDTO;
-import org.apache.bigtop.manager.server.model.dto.ServiceDTO;
 
-import jakarta.annotation.Resource;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 
-public abstract class AbstractComponentStageFactory extends AbstractStageFactory {
+public abstract class AbstractComponentTask extends AbstractTask {
 
-    @Resource
-    private ClusterRepository clusterRepository;
+    protected HostComponentRepository hostComponentRepository;
 
-    protected ClusterPO clusterPO;
+    public AbstractComponentTask(TaskContext taskContext) {
+        super(taskContext);
+    }
 
     @Override
-    public void doCreateStage() {
-        clusterPO = clusterRepository.getReferenceById(context.getClusterId());
-
-        Command command = getCommand();
-        ServiceDTO serviceDTO = context.getServiceDTO();
-        ComponentDTO componentDTO = context.getComponentDTO();
-
-        stagePO.setName(command.toCamelCase() + " " + componentDTO.getDisplayName());
-        stagePO.setServiceName(serviceDTO.getServiceName());
-        stagePO.setComponentName(componentDTO.getComponentName());
-
-        List<TaskPO> taskPOList = new ArrayList<>();
-        for (String hostname : context.getHostnames()) {
-            TaskPO taskPO = new TaskPO();
-
-            // Required fields
-            taskPO.setName(stagePO.getName() + " on " + hostname);
-            taskPO.setHostname(hostname);
-            taskPO.setCommand(command);
-            taskPO.setServiceName(serviceDTO.getServiceName());
-            taskPO.setStackName(context.getStackName());
-            taskPO.setStackVersion(context.getStackVersion());
-
-            // Context fields
-            taskPO.setComponentName(componentDTO.getComponentName());
-            taskPO.setServiceUser(serviceDTO.getServiceUser());
-            taskPO.setServiceGroup(serviceDTO.getServiceGroup());
-            taskPO.setCustomCommands(JsonUtils.writeAsString(componentDTO.getCustomCommands()));
-            taskPO.setCommandScript(JsonUtils.writeAsString(componentDTO.getCommandScript()));
-
-            CommandRequest request = getMessage(serviceDTO, componentDTO, hostname, command);
-            taskPO.setContent(ProtobufUtil.toJson(request));
-            taskPOList.add(taskPO);
-        }
+    protected void injectBeans() {
+        super.injectBeans();
 
-        stagePO.setTaskPOList(taskPOList);
+        this.hostComponentRepository = SpringContextHolder.getBean(HostComponentRepository.class);
     }
 
-    protected abstract Command getCommand();
-
-    private CommandRequest getMessage(
-            ServiceDTO serviceDTO, ComponentDTO componentDTO, String hostname, Command command) {
+    @Override
+    @SuppressWarnings("unchecked")
+    protected CommandRequest getCommandRequest() {
         CommandPayload commandPayload = new CommandPayload();
-        commandPayload.setServiceName(serviceDTO.getServiceName());
-        commandPayload.setCommand(command);
-        commandPayload.setServiceUser(serviceDTO.getServiceUser());
-        commandPayload.setServiceGroup(serviceDTO.getServiceGroup());
-        commandPayload.setStackName(context.getStackName());
-        commandPayload.setStackVersion(context.getStackVersion());
-        commandPayload.setComponentName(componentDTO.getComponentName());
-        commandPayload.setRoot(clusterPO.getRoot());
-        commandPayload.setHostname(hostname);
-
-        commandPayload.setCustomCommands(convertCustomCommandInfo(componentDTO.getCustomCommands()));
-        commandPayload.setOsSpecifics(convertOSSpecificInfo(serviceDTO.getOsSpecifics()));
-        commandPayload.setCommandScript(convertScriptInfo(componentDTO.getCommandScript()));
+        commandPayload.setServiceName(taskContext.getServiceName());
+        commandPayload.setCommand(getCommand());
+        commandPayload.setServiceUser(taskContext.getServiceUser());
+        commandPayload.setServiceGroup(taskContext.getServiceGroup());
+        commandPayload.setStackName(taskContext.getStackName());
+        commandPayload.setStackVersion(taskContext.getStackVersion());
+        commandPayload.setComponentName(taskContext.getComponentName());
+        commandPayload.setRoot(taskContext.getRoot());
+        commandPayload.setHostname(taskContext.getHostname());
+
+        Map<String, Object> properties = taskContext.getProperties();
+
+        commandPayload.setCustomCommands(
+                convertCustomCommandInfo((List<CustomCommandDTO>) properties.get("customCommands")));
+        commandPayload.setOsSpecifics(convertOSSpecificInfo((List<OSSpecificDTO>) properties.get("osSpecifics")));
+        commandPayload.setCommandScript(convertScriptInfo((ScriptDTO) properties.get("commandScript")));
 
         CommandRequest.Builder builder = CommandRequest.newBuilder();
         builder.setType(CommandType.COMPONENT);
-        builder.setHostname(hostname);
+        builder.setHostname(taskContext.getHostname());
         builder.setPayload(JsonUtils.writeAsString(commandPayload));
 
         return builder.build();
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/AbstractTask.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/AbstractTask.java
new file mode 100644
index 0000000..d9d0fee
--- /dev/null
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/AbstractTask.java
@@ -0,0 +1,140 @@
+/*
+ * 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
+ *
+ *    https://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.bigtop.manager.server.command.task;
+
+import org.apache.bigtop.manager.common.constants.MessageConstants;
+import org.apache.bigtop.manager.common.enums.Command;
+import org.apache.bigtop.manager.common.enums.JobState;
+import org.apache.bigtop.manager.common.utils.JsonUtils;
+import org.apache.bigtop.manager.dao.po.TaskPO;
+import org.apache.bigtop.manager.dao.repository.TaskRepository;
+import org.apache.bigtop.manager.grpc.generated.CommandReply;
+import org.apache.bigtop.manager.grpc.generated.CommandRequest;
+import org.apache.bigtop.manager.grpc.generated.CommandServiceGrpc;
+import org.apache.bigtop.manager.grpc.utils.ProtobufUtil;
+import org.apache.bigtop.manager.server.grpc.GrpcClient;
+import org.apache.bigtop.manager.server.holder.SpringContextHolder;
+
+public abstract class AbstractTask implements Task {
+
+    protected TaskRepository taskRepository;
+
+    protected TaskContext taskContext;
+
+    protected CommandRequest commandRequest;
+
+    /**
+     * Do not use this directly, please use {@link #getTaskPO()} to make sure it's initialized.
+     */
+    private TaskPO taskPO;
+
+    public AbstractTask(TaskContext taskContext) {
+        this.taskContext = taskContext;
+
+        injectBeans();
+    }
+
+    protected void injectBeans() {
+        this.taskRepository = SpringContextHolder.getBean(TaskRepository.class);
+    }
+
+    protected abstract Command getCommand();
+
+    protected String getCustomCommand() {
+        return null;
+    }
+
+    protected abstract CommandRequest getCommandRequest();
+
+    @Override
+    public void beforeRun() {
+        TaskPO taskPO = getTaskPO();
+        taskPO.setState(JobState.PROCESSING);
+        taskRepository.save(taskPO);
+    }
+
+    @Override
+    public Boolean run() {
+        beforeRun();
+
+        CommandRequest.Builder builder = CommandRequest.newBuilder(getCommandRequest());
+        builder.setTaskId(getTaskPO().getId());
+        commandRequest = builder.build();
+
+        CommandServiceGrpc.CommandServiceBlockingStub stub = GrpcClient.getBlockingStub(
+                taskContext.getHostname(), CommandServiceGrpc.CommandServiceBlockingStub.class);
+        CommandReply reply = stub.exec(commandRequest);
+
+        boolean taskSuccess = reply != null && reply.getCode() == MessageConstants.SUCCESS_CODE;
+
+        if (taskSuccess) {
+            onSuccess();
+        } else {
+            onFailure();
+        }
+
+        return taskSuccess;
+    }
+
+    @Override
+    public void onSuccess() {
+        TaskPO taskPO = getTaskPO();
+        taskPO.setContent(ProtobufUtil.toJson(commandRequest));
+        taskPO.setState(JobState.SUCCESSFUL);
+        taskRepository.save(taskPO);
+    }
+
+    @Override
+    public void onFailure() {
+        TaskPO taskPO = getTaskPO();
+        taskPO.setContent(ProtobufUtil.toJson(commandRequest));
+        taskPO.setState(JobState.FAILED);
+        taskRepository.save(taskPO);
+    }
+
+    @Override
+    public TaskContext getTaskContext() {
+        return taskContext;
+    }
+
+    @Override
+    public void loadTaskPO(TaskPO taskPO) {
+        this.taskPO = taskPO;
+    }
+
+    @Override
+    public TaskPO getTaskPO() {
+        if (taskPO == null) {
+            taskPO = new TaskPO();
+            taskPO.setName(getName());
+            taskPO.setContext(JsonUtils.writeAsString(taskContext));
+            taskPO.setStackName(taskContext.getStackName());
+            taskPO.setStackVersion(taskContext.getStackVersion());
+            taskPO.setHostname(taskContext.getHostname());
+            taskPO.setServiceName(taskContext.getServiceName());
+            taskPO.setServiceUser(taskContext.getServiceUser());
+            taskPO.setServiceGroup(taskContext.getServiceGroup());
+            taskPO.setComponentName(taskContext.getComponentName());
+            taskPO.setCommand(getCommand());
+            taskPO.setCustomCommand(getCustomCommand());
+        }
+
+        return taskPO;
+    }
+}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/runner/config/CacheDistributeStageRunner.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/CacheFileUpdateTask.java
similarity index 79%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/runner/config/CacheDistributeStageRunner.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/CacheFileUpdateTask.java
index a4cc566..5dbe5e9 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/runner/config/CacheDistributeStageRunner.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/CacheFileUpdateTask.java
@@ -16,9 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.stage.runner.config;
+package org.apache.bigtop.manager.server.command.task;
 
 import org.apache.bigtop.manager.common.constants.Constants;
+import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.common.message.entity.payload.CacheMessagePayload;
 import org.apache.bigtop.manager.common.message.entity.pojo.ClusterInfo;
 import org.apache.bigtop.manager.common.message.entity.pojo.ComponentInfo;
@@ -32,7 +33,6 @@ import org.apache.bigtop.manager.dao.po.RepoPO;
 import org.apache.bigtop.manager.dao.po.ServiceConfigPO;
 import org.apache.bigtop.manager.dao.po.ServicePO;
 import org.apache.bigtop.manager.dao.po.SettingPO;
-import org.apache.bigtop.manager.dao.po.TaskPO;
 import org.apache.bigtop.manager.dao.po.TypeConfigPO;
 import org.apache.bigtop.manager.dao.repository.ClusterRepository;
 import org.apache.bigtop.manager.dao.repository.ComponentRepository;
@@ -44,11 +44,10 @@ import org.apache.bigtop.manager.dao.repository.ServiceRepository;
 import org.apache.bigtop.manager.dao.repository.SettingRepository;
 import org.apache.bigtop.manager.grpc.generated.CommandRequest;
 import org.apache.bigtop.manager.grpc.generated.CommandType;
-import org.apache.bigtop.manager.grpc.utils.ProtobufUtil;
-import org.apache.bigtop.manager.server.command.stage.factory.StageType;
-import org.apache.bigtop.manager.server.command.stage.runner.AbstractStageRunner;
+import org.apache.bigtop.manager.server.holder.SpringContextHolder;
 import org.apache.bigtop.manager.server.model.converter.RepoConverter;
 import org.apache.bigtop.manager.server.model.dto.PropertyDTO;
+import org.apache.bigtop.manager.server.model.dto.RepoDTO;
 import org.apache.bigtop.manager.server.model.dto.ServiceDTO;
 import org.apache.bigtop.manager.server.model.dto.StackDTO;
 import org.apache.bigtop.manager.server.utils.StackConfigUtils;
@@ -56,13 +55,8 @@ import org.apache.bigtop.manager.server.utils.StackUtils;
 
 import org.apache.commons.lang3.tuple.ImmutablePair;
 
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Scope;
-
 import com.fasterxml.jackson.core.type.TypeReference;
-import lombok.extern.slf4j.Slf4j;
 
-import jakarta.annotation.Resource;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -73,77 +67,60 @@ import java.util.stream.Collectors;
 
 import static org.apache.bigtop.manager.common.constants.Constants.ALL_HOST_KEY;
 
-@Slf4j
-@org.springframework.stereotype.Component
-@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class CacheDistributeStageRunner extends AbstractStageRunner {
+public class CacheFileUpdateTask extends AbstractTask {
 
-    @Resource
     private ClusterRepository clusterRepository;
-
-    @Resource
     private HostComponentRepository hostComponentRepository;
-
-    @Resource
     private ServiceRepository serviceRepository;
-
-    @Resource
     private ServiceConfigRepository serviceConfigRepository;
-
-    @Resource
     private RepoRepository repoRepository;
-
-    @Resource
     private SettingRepository settingRepository;
-
-    @Resource
     private HostRepository hostRepository;
-
-    @Resource
     private ComponentRepository componentRepository;
 
     private ClusterInfo clusterInfo;
-
     private Map<String, ComponentInfo> componentInfoMap;
-
     private Map<String, Map<String, Object>> serviceConfigMap;
-
     private Map<String, Set<String>> hostMap;
-
     private List<RepoInfo> repoList;
-
     private Map<String, Set<String>> userMap;
-
     private Map<String, Object> settingsMap;
 
+    public CacheFileUpdateTask(TaskContext taskContext) {
+        super(taskContext);
+    }
+
     @Override
-    public StageType getStageType() {
-        return StageType.CACHE_DISTRIBUTE;
+    protected void injectBeans() {
+        super.injectBeans();
+
+        this.clusterRepository = SpringContextHolder.getBean(ClusterRepository.class);
+        this.hostComponentRepository = SpringContextHolder.getBean(HostComponentRepository.class);
+        this.serviceRepository = SpringContextHolder.getBean(ServiceRepository.class);
+        this.serviceConfigRepository = SpringContextHolder.getBean(ServiceConfigRepository.class);
+        this.repoRepository = SpringContextHolder.getBean(RepoRepository.class);
+        this.settingRepository = SpringContextHolder.getBean(SettingRepository.class);
+        this.hostRepository = SpringContextHolder.getBean(HostRepository.class);
+        this.componentRepository = SpringContextHolder.getBean(ComponentRepository.class);
     }
 
     @Override
-    public void beforeRunTask(TaskPO taskPO) {
-        super.beforeRunTask(taskPO);
+    public void beforeRun() {
+        super.beforeRun();
 
-        // Generate task content before execute
-        updateTask(taskPO);
+        genCaches();
     }
 
-    private void updateTask(TaskPO taskPO) {
-        if (stageContext.getClusterId() == null) {
+    private void genCaches() {
+        if (taskContext.getClusterId() == null) {
             genEmptyCaches();
         } else {
-            genCaches();
+            genFullCaches();
         }
-
-        CommandRequest request = getMessage(taskPO.getHostname());
-        taskPO.setContent(ProtobufUtil.toJson(request));
-
-        taskRepository.save(taskPO);
     }
 
-    private void genCaches() {
-        ClusterPO clusterPO = clusterRepository.getReferenceById(stageContext.getClusterId());
+    private void genFullCaches() {
+        ClusterPO clusterPO = clusterRepository.getReferenceById(taskContext.getClusterId());
 
         Long clusterId = clusterPO.getId();
         String clusterName = clusterPO.getClusterName();
@@ -228,6 +205,7 @@ public class CacheDistributeStageRunner extends AbstractStageRunner {
         });
     }
 
+    @SuppressWarnings("unchecked")
     private void genEmptyCaches() {
         componentInfoMap = new HashMap<>();
         serviceConfigMap = new HashMap<>();
@@ -235,22 +213,24 @@ public class CacheDistributeStageRunner extends AbstractStageRunner {
         userMap = new HashMap<>();
         settingsMap = new HashMap<>();
 
-        String fullStackName = StackUtils.fullStackName(stageContext.getStackName(), stageContext.getStackVersion());
+        String fullStackName = StackUtils.fullStackName(taskContext.getStackName(), taskContext.getStackVersion());
         ImmutablePair<StackDTO, List<ServiceDTO>> immutablePair =
                 StackUtils.getStackKeyMap().get(fullStackName);
         StackDTO stackDTO = immutablePair.getLeft();
         List<ServiceDTO> serviceDTOList = immutablePair.getRight();
 
-        repoList = RepoConverter.INSTANCE.fromDTO2Message(stageContext.getRepoInfoList());
+        Map<String, Object> properties = taskContext.getProperties();
+
+        repoList = RepoConverter.INSTANCE.fromDTO2Message((List<RepoDTO>) properties.get("repoInfoList"));
         clusterInfo = new ClusterInfo();
-        clusterInfo.setClusterName(stageContext.getClusterName());
-        clusterInfo.setStackName(stageContext.getStackName());
-        clusterInfo.setStackVersion(stageContext.getStackVersion());
+        clusterInfo.setClusterName(taskContext.getClusterName());
+        clusterInfo.setStackName(taskContext.getStackName());
+        clusterInfo.setStackVersion(taskContext.getStackVersion());
         clusterInfo.setUserGroup(stackDTO.getUserGroup());
         clusterInfo.setRepoTemplate(stackDTO.getRepoTemplate());
         clusterInfo.setRoot(stackDTO.getRoot());
 
-        List<String> hostnames = stageContext.getHostnames();
+        List<String> hostnames = (List<String>) properties.get("hostnames");
         hostMap.put(Constants.ALL_HOST_KEY, new HashSet<>(hostnames));
 
         for (ServiceDTO serviceDTO : serviceDTOList) {
@@ -258,9 +238,20 @@ public class CacheDistributeStageRunner extends AbstractStageRunner {
         }
     }
 
-    private CommandRequest getMessage(String hostname) {
+    @Override
+    protected Command getCommand() {
+        return Command.CUSTOM;
+    }
+
+    @Override
+    protected String getCustomCommand() {
+        return "update_cache_files";
+    }
+
+    @Override
+    protected CommandRequest getCommandRequest() {
         CacheMessagePayload messagePayload = new CacheMessagePayload();
-        messagePayload.setHostname(hostname);
+        messagePayload.setHostname(taskContext.getHostname());
         messagePayload.setClusterInfo(clusterInfo);
         messagePayload.setConfigurations(serviceConfigMap);
         messagePayload.setClusterHostInfo(hostMap);
@@ -270,10 +261,15 @@ public class CacheDistributeStageRunner extends AbstractStageRunner {
         messagePayload.setComponentInfo(componentInfoMap);
 
         CommandRequest.Builder builder = CommandRequest.newBuilder();
-        builder.setType(CommandType.CACHE_DISTRIBUTE);
-        builder.setHostname(hostname);
+        builder.setType(CommandType.UPDATE_CACHE_FILES);
+        builder.setHostname(taskContext.getHostname());
         builder.setPayload(JsonUtils.writeAsString(messagePayload));
 
         return builder.build();
     }
+
+    @Override
+    public String getName() {
+        return "Update cache files on " + taskContext.getHostname();
+    }
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/component/ComponentCheckStageFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/ComponentCheckTask.java
similarity index 63%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/component/ComponentCheckStageFactory.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/ComponentCheckTask.java
index 8f6c1f7..121b5b9 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/component/ComponentCheckStageFactory.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/ComponentCheckTask.java
@@ -16,28 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.stage.factory.component;
+package org.apache.bigtop.manager.server.command.task;
 
 import org.apache.bigtop.manager.common.enums.Command;
-import org.apache.bigtop.manager.server.command.stage.factory.StageType;
 
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Scope;
+public class ComponentCheckTask extends AbstractComponentTask {
 
-import lombok.extern.slf4j.Slf4j;
-
-@Slf4j
-@org.springframework.stereotype.Component
-@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class ComponentCheckStageFactory extends AbstractComponentStageFactory {
-
-    @Override
-    public StageType getStageType() {
-        return StageType.COMPONENT_CHECK;
+    public ComponentCheckTask(TaskContext taskContext) {
+        super(taskContext);
     }
 
     @Override
     protected Command getCommand() {
         return Command.CHECK;
     }
+
+    @Override
+    public String getName() {
+        return "Check " + taskContext.getComponentDisplayName() + " on " + taskContext.getHostname();
+    }
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/runner/component/ComponentInstallStageRunner.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/ComponentInstallTask.java
similarity index 53%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/runner/component/ComponentInstallStageRunner.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/ComponentInstallTask.java
index c2a15fa..8bc9530 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/runner/component/ComponentInstallStageRunner.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/ComponentInstallTask.java
@@ -16,46 +16,39 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.stage.runner.component;
+package org.apache.bigtop.manager.server.command.task;
 
+import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.common.enums.MaintainState;
 import org.apache.bigtop.manager.dao.po.HostComponentPO;
-import org.apache.bigtop.manager.dao.po.TaskPO;
-import org.apache.bigtop.manager.dao.repository.HostComponentRepository;
-import org.apache.bigtop.manager.server.command.stage.factory.StageType;
-import org.apache.bigtop.manager.server.command.stage.runner.AbstractStageRunner;
 
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Scope;
+public class ComponentInstallTask extends AbstractComponentTask {
 
-import lombok.extern.slf4j.Slf4j;
-
-import jakarta.annotation.Resource;
-
-@Slf4j
-@org.springframework.stereotype.Component
-@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class ComponentInstallStageRunner extends AbstractStageRunner {
-
-    @Resource
-    private HostComponentRepository hostComponentRepository;
+    public ComponentInstallTask(TaskContext taskContext) {
+        super(taskContext);
+    }
 
     @Override
-    public StageType getStageType() {
-        return StageType.COMPONENT_INSTALL;
+    protected Command getCommand() {
+        return Command.INSTALL;
     }
 
     @Override
-    public void onTaskSuccess(TaskPO taskPO) {
-        super.onTaskSuccess(taskPO);
+    public void onSuccess() {
+        super.onSuccess();
 
-        Long clusterId = taskPO.getClusterPO().getId();
-        String componentName = taskPO.getComponentName();
-        String hostname = taskPO.getHostname();
+        Long clusterId = taskContext.getClusterId();
+        String componentName = taskContext.getComponentName();
+        String hostname = taskContext.getHostname();
         HostComponentPO hostComponentPO =
                 hostComponentRepository.findByComponentPOClusterPOIdAndComponentPOComponentNameAndHostPOHostname(
                         clusterId, componentName, hostname);
         hostComponentPO.setState(MaintainState.INSTALLED);
         hostComponentRepository.save(hostComponentPO);
     }
+
+    @Override
+    public String getName() {
+        return "Install " + taskContext.getComponentDisplayName() + " on " + taskContext.getHostname();
+    }
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/runner/component/ComponentStartStageRunner.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/ComponentStartTask.java
similarity index 55%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/runner/component/ComponentStartStageRunner.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/ComponentStartTask.java
index b070c32..3160fe8 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/runner/component/ComponentStartStageRunner.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/ComponentStartTask.java
@@ -16,42 +16,30 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.stage.runner.component;
+package org.apache.bigtop.manager.server.command.task;
 
+import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.common.enums.MaintainState;
 import org.apache.bigtop.manager.dao.po.HostComponentPO;
-import org.apache.bigtop.manager.dao.po.TaskPO;
-import org.apache.bigtop.manager.dao.repository.HostComponentRepository;
-import org.apache.bigtop.manager.server.command.stage.factory.StageType;
-import org.apache.bigtop.manager.server.command.stage.runner.AbstractStageRunner;
 
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Scope;
+public class ComponentStartTask extends AbstractComponentTask {
 
-import lombok.extern.slf4j.Slf4j;
-
-import jakarta.annotation.Resource;
-
-@Slf4j
-@org.springframework.stereotype.Component
-@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class ComponentStartStageRunner extends AbstractStageRunner {
-
-    @Resource
-    private HostComponentRepository hostComponentRepository;
+    public ComponentStartTask(TaskContext taskContext) {
+        super(taskContext);
+    }
 
     @Override
-    public StageType getStageType() {
-        return StageType.COMPONENT_START;
+    protected Command getCommand() {
+        return Command.START;
     }
 
     @Override
-    public void onTaskSuccess(TaskPO taskPO) {
-        super.onTaskSuccess(taskPO);
+    public void onSuccess() {
+        super.onSuccess();
 
-        Long clusterId = taskPO.getClusterPO().getId();
-        String componentName = taskPO.getComponentName();
-        String hostname = taskPO.getHostname();
+        Long clusterId = taskContext.getClusterId();
+        String componentName = taskContext.getComponentName();
+        String hostname = taskContext.getHostname();
         HostComponentPO hostComponentPO =
                 hostComponentRepository.findByComponentPOClusterPOIdAndComponentPOComponentNameAndHostPOHostname(
                         clusterId, componentName, hostname);
@@ -60,7 +48,7 @@ public class ComponentStartStageRunner extends AbstractStageRunner {
     }
 
     @Override
-    public void onSuccess() {
-        super.onSuccess();
+    public String getName() {
+        return "Start " + taskContext.getComponentDisplayName() + " on " + taskContext.getHostname();
     }
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/runner/component/ComponentStopStageRunner.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/ComponentStopTask.java
similarity index 54%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/runner/component/ComponentStopStageRunner.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/ComponentStopTask.java
index 9ebfbf4..3c946fe 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/runner/component/ComponentStopStageRunner.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/ComponentStopTask.java
@@ -16,46 +16,39 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.stage.runner.component;
+package org.apache.bigtop.manager.server.command.task;
 
+import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.common.enums.MaintainState;
 import org.apache.bigtop.manager.dao.po.HostComponentPO;
-import org.apache.bigtop.manager.dao.po.TaskPO;
-import org.apache.bigtop.manager.dao.repository.HostComponentRepository;
-import org.apache.bigtop.manager.server.command.stage.factory.StageType;
-import org.apache.bigtop.manager.server.command.stage.runner.AbstractStageRunner;
 
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Scope;
+public class ComponentStopTask extends AbstractComponentTask {
 
-import lombok.extern.slf4j.Slf4j;
-
-import jakarta.annotation.Resource;
-
-@Slf4j
-@org.springframework.stereotype.Component
-@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class ComponentStopStageRunner extends AbstractStageRunner {
-
-    @Resource
-    private HostComponentRepository hostComponentRepository;
+    public ComponentStopTask(TaskContext taskContext) {
+        super(taskContext);
+    }
 
     @Override
-    public StageType getStageType() {
-        return StageType.COMPONENT_STOP;
+    protected Command getCommand() {
+        return Command.STOP;
     }
 
     @Override
-    public void onTaskSuccess(TaskPO taskPO) {
-        super.onTaskSuccess(taskPO);
+    public void onSuccess() {
+        super.onSuccess();
 
-        Long clusterId = taskPO.getClusterPO().getId();
-        String componentName = taskPO.getComponentName();
-        String hostname = taskPO.getHostname();
+        Long clusterId = taskContext.getClusterId();
+        String componentName = taskContext.getComponentName();
+        String hostname = taskContext.getHostname();
         HostComponentPO hostComponentPO =
                 hostComponentRepository.findByComponentPOClusterPOIdAndComponentPOComponentNameAndHostPOHostname(
                         clusterId, componentName, hostname);
         hostComponentPO.setState(MaintainState.STOPPED);
         hostComponentRepository.save(hostComponentPO);
     }
+
+    @Override
+    public String getName() {
+        return "Stop " + taskContext.getComponentDisplayName() + " on " + taskContext.getHostname();
+    }
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/HostCheckTask.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/HostCheckTask.java
new file mode 100644
index 0000000..da9a207
--- /dev/null
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/HostCheckTask.java
@@ -0,0 +1,61 @@
+/*
+ * 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
+ *
+ *    https://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.bigtop.manager.server.command.task;
+
+import org.apache.bigtop.manager.common.enums.Command;
+import org.apache.bigtop.manager.common.message.entity.payload.HostCheckPayload;
+import org.apache.bigtop.manager.common.utils.JsonUtils;
+import org.apache.bigtop.manager.grpc.generated.CommandRequest;
+import org.apache.bigtop.manager.grpc.generated.CommandType;
+
+public class HostCheckTask extends AbstractTask {
+
+    public HostCheckTask(TaskContext taskContext) {
+        super(taskContext);
+    }
+
+    @Override
+    protected Command getCommand() {
+        return Command.CUSTOM;
+    }
+
+    @Override
+    protected String getCustomCommand() {
+        return "check_host";
+    }
+
+    @Override
+    protected CommandRequest getCommandRequest() {
+        String hostname = taskContext.getHostname();
+        HostCheckPayload messagePayload = new HostCheckPayload();
+        messagePayload.setHostname(hostname);
+
+        CommandRequest.Builder builder = CommandRequest.newBuilder();
+        builder.setType(CommandType.HOST_CHECK);
+        builder.setHostname(hostname);
+        builder.setPayload(JsonUtils.writeAsString(messagePayload));
+
+        return builder.build();
+    }
+
+    @Override
+    public String getName() {
+        return "Check host " + taskContext.getHostname();
+    }
+}
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/StageType.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/Task.java
similarity index 71%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/StageType.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/Task.java
index dc12b71..7b1a572 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/StageType.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/Task.java
@@ -16,23 +16,25 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.stage.factory;
+package org.apache.bigtop.manager.server.command.task;
 
-public enum StageType {
-    HOST_CHECK,
+import org.apache.bigtop.manager.dao.po.TaskPO;
 
-    CACHE_DISTRIBUTE,
+public interface Task {
 
-    COMPONENT_INSTALL,
+    String getName();
 
-    COMPONENT_START,
+    void beforeRun();
 
-    COMPONENT_STOP,
+    Boolean run();
 
-    COMPONENT_CHECK,
+    void onSuccess();
 
-    SERVICE_CHECK,
+    void onFailure();
 
-    SERVICE_CONFIGURE,
-    ;
+    TaskContext getTaskContext();
+
+    void loadTaskPO(TaskPO taskPO);
+
+    TaskPO getTaskPO();
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/component/ComponentStopStageFactory.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/TaskContext.java
similarity index 56%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/component/ComponentStopStageFactory.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/TaskContext.java
index 232a374..1447736 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/factory/component/ComponentStopStageFactory.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/TaskContext.java
@@ -16,28 +16,43 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.stage.factory.component;
+package org.apache.bigtop.manager.server.command.task;
 
 import org.apache.bigtop.manager.common.enums.Command;
-import org.apache.bigtop.manager.server.command.stage.factory.StageType;
 
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Scope;
+import lombok.Data;
 
-import lombok.extern.slf4j.Slf4j;
+import java.util.Map;
 
-@Slf4j
-@org.springframework.stereotype.Component
-@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class ComponentStopStageFactory extends AbstractComponentStageFactory {
+@Data
+public class TaskContext {
 
-    @Override
-    public StageType getStageType() {
-        return StageType.COMPONENT_STOP;
-    }
+    private Long clusterId;
 
-    @Override
-    protected Command getCommand() {
-        return Command.STOP;
-    }
+    private String clusterName;
+
+    private String hostname;
+
+    private String stackName;
+
+    private String stackVersion;
+
+    private String serviceName;
+
+    private String serviceUser;
+
+    private String serviceGroup;
+
+    private String componentName;
+
+    private String componentDisplayName;
+
+    private Command command;
+
+    private String customCommand;
+
+    private String root;
+
+    // Extra properties for specific tasks
+    protected Map<String, Object> properties;
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/ClusterCreateValidator.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/validator/ClusterCreateValidator.java
similarity index 97%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/ClusterCreateValidator.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/validator/ClusterCreateValidator.java
index 7b0cd08..9229e17 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/ClusterCreateValidator.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/validator/ClusterCreateValidator.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.validator;
+package org.apache.bigtop.manager.server.command.validator;
 
 import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.dao.po.ClusterPO;
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/ClusterHostValidator.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/validator/ClusterHostValidator.java
similarity index 97%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/ClusterHostValidator.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/validator/ClusterHostValidator.java
index bc1f933..9d2509f 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/ClusterHostValidator.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/validator/ClusterHostValidator.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.validator;
+package org.apache.bigtop.manager.server.command.validator;
 
 import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.dao.po.HostPO;
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/CommandValidator.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/validator/CommandValidator.java
similarity index 94%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/CommandValidator.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/validator/CommandValidator.java
index 0fe4dba..87edf23 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/CommandValidator.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/validator/CommandValidator.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.validator;
+package org.apache.bigtop.manager.server.command.validator;
 
 import org.apache.bigtop.manager.server.command.CommandIdentifier;
 
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/HostAddValidator.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/validator/HostAddValidator.java
similarity index 97%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/HostAddValidator.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/validator/HostAddValidator.java
index a8d59b9..c57c734 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/HostAddValidator.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/validator/HostAddValidator.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.validator;
+package org.apache.bigtop.manager.server.command.validator;
 
 import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.dao.po.HostPO;
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/RequiredServicesValidator.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/validator/RequiredServicesValidator.java
similarity index 98%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/RequiredServicesValidator.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/validator/RequiredServicesValidator.java
index 7a5f927..8248578 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/RequiredServicesValidator.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/validator/RequiredServicesValidator.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.validator;
+package org.apache.bigtop.manager.server.command.validator;
 
 import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.dao.po.ClusterPO;
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/ServiceHostValidator.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/validator/ServiceHostValidator.java
similarity index 97%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/ServiceHostValidator.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/validator/ServiceHostValidator.java
index 7611e6d..f6a4dd1 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/ServiceHostValidator.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/validator/ServiceHostValidator.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.validator;
+package org.apache.bigtop.manager.server.command.validator;
 
 import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.dao.po.HostPO;
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/StackValidator.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/validator/StackValidator.java
similarity index 97%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/StackValidator.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/validator/StackValidator.java
index 498af0f..42404c0 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/StackValidator.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/validator/StackValidator.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.validator;
+package org.apache.bigtop.manager.server.command.validator;
 
 import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.dao.po.StackPO;
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/ValidatorContext.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/validator/ValidatorContext.java
similarity index 93%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/ValidatorContext.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/validator/ValidatorContext.java
index 09ecd45..c83704f 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/ValidatorContext.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/validator/ValidatorContext.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.validator;
+package org.apache.bigtop.manager.server.command.validator;
 
 import org.apache.bigtop.manager.server.model.dto.CommandDTO;
 
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/ValidatorExecutionChain.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/validator/ValidatorExecutionChain.java
similarity index 95%
rename from bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/ValidatorExecutionChain.java
rename to bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/validator/ValidatorExecutionChain.java
index 797ad8d..0323bb4 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/validator/ValidatorExecutionChain.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/validator/ValidatorExecutionChain.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.validator;
+package org.apache.bigtop.manager.server.command.validator;
 
 import org.apache.bigtop.manager.server.command.CommandIdentifier;
 import org.apache.bigtop.manager.server.holder.SpringContextHolder;
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/holder/SpringContextHolder.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/holder/SpringContextHolder.java
index 4143720..381ba68 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/holder/SpringContextHolder.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/holder/SpringContextHolder.java
@@ -18,11 +18,8 @@
  */
 package org.apache.bigtop.manager.server.holder;
 
-import org.apache.bigtop.manager.server.command.job.factory.JobFactory;
-import org.apache.bigtop.manager.server.command.job.runner.JobRunner;
-import org.apache.bigtop.manager.server.command.job.validator.CommandValidator;
-import org.apache.bigtop.manager.server.command.stage.factory.StageFactory;
-import org.apache.bigtop.manager.server.command.stage.runner.StageRunner;
+import org.apache.bigtop.manager.server.command.factory.JobFactory;
+import org.apache.bigtop.manager.server.command.validator.CommandValidator;
 
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationContextAware;
@@ -44,6 +41,10 @@ public class SpringContextHolder implements ApplicationContextAware {
         SpringContextHolder.applicationContext = applicationContext;
     }
 
+    public static <T> T getBean(Class<T> clazz) {
+        return applicationContext.getBean(clazz);
+    }
+
     public static Map<String, CommandValidator> getCommandValidators() {
         return applicationContext.getBeansOfType(CommandValidator.class);
     }
@@ -51,16 +52,4 @@ public class SpringContextHolder implements ApplicationContextAware {
     public static Map<String, JobFactory> getJobFactories() {
         return applicationContext.getBeansOfType(JobFactory.class);
     }
-
-    public static Map<String, JobRunner> getJobRunners() {
-        return applicationContext.getBeansOfType(JobRunner.class);
-    }
-
-    public static Map<String, StageFactory> getStageFactories() {
-        return applicationContext.getBeansOfType(StageFactory.class);
-    }
-
-    public static Map<String, StageRunner> getStageRunners() {
-        return applicationContext.getBeansOfType(StageRunner.class);
-    }
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/converter/ClusterConverter.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/converter/ClusterConverter.java
index 635181e..b093dfd 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/converter/ClusterConverter.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/converter/ClusterConverter.java
@@ -43,6 +43,8 @@ public interface ClusterConverter {
 
     ClusterPO fromDTO2PO(ClusterDTO clusterDTO);
 
+    ClusterDTO fromPO2DTO(ClusterPO clusterPO);
+
     @Mapping(target = "stackName", source = "stackPO.stackName")
     @Mapping(target = "stackVersion", source = "stackPO.stackVersion")
     ClusterVO fromEntity2VO(ClusterPO clusterPO);
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/dto/command/ServiceCommandDTO.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/dto/command/ServiceCommandDTO.java
index ea687df..4ffa1e9 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/dto/command/ServiceCommandDTO.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/dto/command/ServiceCommandDTO.java
@@ -31,6 +31,8 @@ public class ServiceCommandDTO implements Serializable {
 
     private String serviceName;
 
+    private Boolean installed;
+
     private String configDesc;
 
     private Integer version;
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/req/command/ServiceCommandReq.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/req/command/ServiceCommandReq.java
index ebb015b..499c605 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/req/command/ServiceCommandReq.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/req/command/ServiceCommandReq.java
@@ -36,6 +36,9 @@ public class ServiceCommandReq {
     @NotNull @Schema(description = "Service name", example = "zookeeper")
     private String serviceName;
 
+    @Schema(description = "If service installed", example = "true")
+    private Boolean installed;
+
     @Schema(description = "Config Description", example = "Initial config for zookeeper")
     private String configDesc;
 
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/scheduler/ComponentStatusScheduler.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/scheduler/ComponentStatusScheduler.java
index 9759865..9ef5683 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/scheduler/ComponentStatusScheduler.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/scheduler/ComponentStatusScheduler.java
@@ -33,6 +33,7 @@ import org.apache.bigtop.manager.server.grpc.GrpcClient;
 
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
 
 import lombok.extern.slf4j.Slf4j;
 
@@ -41,7 +42,7 @@ import java.util.List;
 import java.util.concurrent.TimeUnit;
 
 @Slf4j
-@org.springframework.stereotype.Component
+@Component
 public class ComponentStatusScheduler {
 
     @Resource
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/ClusterServiceImpl.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/ClusterServiceImpl.java
index 74a5760..7b53820 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/ClusterServiceImpl.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/ClusterServiceImpl.java
@@ -36,6 +36,8 @@ import org.apache.bigtop.manager.server.service.ClusterService;
 import org.apache.bigtop.manager.server.service.HostService;
 import org.apache.bigtop.manager.server.utils.StackUtils;
 
+import org.springframework.stereotype.Service;
+
 import lombok.extern.slf4j.Slf4j;
 
 import jakarta.annotation.Resource;
@@ -43,7 +45,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 @Slf4j
-@org.springframework.stereotype.Service
+@Service
 public class ClusterServiceImpl implements ClusterService {
 
     @Resource
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/CommandServiceImpl.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/CommandServiceImpl.java
index 9eb8037..64d8b02 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/CommandServiceImpl.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/CommandServiceImpl.java
@@ -18,30 +18,55 @@
  */
 package org.apache.bigtop.manager.server.service.impl;
 
+import org.apache.bigtop.manager.common.enums.JobState;
+import org.apache.bigtop.manager.dao.po.ClusterPO;
 import org.apache.bigtop.manager.dao.po.JobPO;
+import org.apache.bigtop.manager.dao.po.StagePO;
+import org.apache.bigtop.manager.dao.po.TaskPO;
+import org.apache.bigtop.manager.dao.repository.ClusterRepository;
+import org.apache.bigtop.manager.dao.repository.JobRepository;
+import org.apache.bigtop.manager.dao.repository.StageRepository;
+import org.apache.bigtop.manager.dao.repository.TaskRepository;
 import org.apache.bigtop.manager.server.command.CommandIdentifier;
-import org.apache.bigtop.manager.server.command.job.factory.JobContext;
-import org.apache.bigtop.manager.server.command.job.factory.JobFactories;
-import org.apache.bigtop.manager.server.command.job.factory.JobFactory;
-import org.apache.bigtop.manager.server.command.job.validator.ValidatorContext;
-import org.apache.bigtop.manager.server.command.job.validator.ValidatorExecutionChain;
+import org.apache.bigtop.manager.server.command.factory.JobFactories;
+import org.apache.bigtop.manager.server.command.factory.JobFactory;
+import org.apache.bigtop.manager.server.command.job.Job;
+import org.apache.bigtop.manager.server.command.job.JobContext;
 import org.apache.bigtop.manager.server.command.scheduler.JobScheduler;
+import org.apache.bigtop.manager.server.command.stage.Stage;
+import org.apache.bigtop.manager.server.command.task.Task;
+import org.apache.bigtop.manager.server.command.validator.ValidatorContext;
+import org.apache.bigtop.manager.server.command.validator.ValidatorExecutionChain;
 import org.apache.bigtop.manager.server.model.converter.JobConverter;
 import org.apache.bigtop.manager.server.model.dto.CommandDTO;
 import org.apache.bigtop.manager.server.model.vo.CommandVO;
 import org.apache.bigtop.manager.server.service.CommandService;
 
+import org.springframework.stereotype.Service;
+
 import lombok.extern.slf4j.Slf4j;
 
 import jakarta.annotation.Resource;
 
 @Slf4j
-@org.springframework.stereotype.Service
+@Service
 public class CommandServiceImpl implements CommandService {
 
     @Resource
     private JobScheduler jobScheduler;
 
+    @Resource
+    private ClusterRepository clusterRepository;
+
+    @Resource
+    private JobRepository jobRepository;
+
+    @Resource
+    private StageRepository stageRepository;
+
+    @Resource
+    private TaskRepository taskRepository;
+
     @Override
     public CommandVO command(CommandDTO commandDTO) {
         CommandIdentifier commandIdentifier =
@@ -56,11 +81,46 @@ public class CommandServiceImpl implements CommandService {
         JobContext jobContext = new JobContext();
         jobContext.setCommandDTO(commandDTO);
         JobFactory jobFactory = JobFactories.getJobFactory(commandIdentifier);
-        JobPO jobPO = jobFactory.createJob(jobContext);
+        Job job = jobFactory.createJob(jobContext);
+
+        // Save job
+        JobPO jobPO = saveJob(job);
 
         // Submit job
-        jobScheduler.submit(jobPO);
+        jobScheduler.submit(job);
 
         return JobConverter.INSTANCE.fromPO2CommandVO(jobPO);
     }
+
+    protected JobPO saveJob(Job job) {
+        Long clusterId = job.getJobContext().getCommandDTO().getClusterId();
+        ClusterPO clusterPO = clusterId == null ? null : clusterRepository.getReferenceById(clusterId);
+
+        JobPO jobPO = job.getJobPO();
+        jobPO.setClusterPO(clusterPO);
+        jobPO.setState(JobState.PENDING);
+        jobRepository.save(jobPO);
+
+        for (int i = 0; i < job.getStages().size(); i++) {
+            Stage stage = job.getStages().get(i);
+            StagePO stagePO = stage.getStagePO();
+            stagePO.setClusterPO(clusterPO);
+            stagePO.setJobPO(jobPO);
+            stagePO.setOrder(i + 1);
+            stagePO.setState(JobState.PENDING);
+            stageRepository.save(stagePO);
+
+            for (int j = 0; j < stage.getTasks().size(); j++) {
+                Task task = stage.getTasks().get(j);
+                TaskPO taskPO = task.getTaskPO();
+                taskPO.setClusterPO(clusterPO);
+                taskPO.setJobPO(jobPO);
+                taskPO.setStagePO(stagePO);
+                taskPO.setState(JobState.PENDING);
+                taskRepository.save(taskPO);
+            }
+        }
+
+        return jobPO;
+    }
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/ConfigServiceImpl.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/ConfigServiceImpl.java
index 45a51da..e06500e 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/ConfigServiceImpl.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/ConfigServiceImpl.java
@@ -35,6 +35,7 @@ import org.apache.bigtop.manager.server.model.vo.ServiceConfigVO;
 import org.apache.bigtop.manager.server.service.ConfigService;
 
 import org.springframework.data.domain.Sort;
+import org.springframework.stereotype.Service;
 
 import lombok.extern.slf4j.Slf4j;
 
@@ -42,7 +43,7 @@ import jakarta.annotation.Resource;
 import java.util.List;
 
 @Slf4j
-@org.springframework.stereotype.Service
+@Service
 public class ConfigServiceImpl implements ConfigService {
 
     @Resource
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/JobServiceImpl.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/JobServiceImpl.java
index fa9fb93..05aa6de 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/JobServiceImpl.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/JobServiceImpl.java
@@ -19,13 +19,21 @@
 package org.apache.bigtop.manager.server.service.impl;
 
 import org.apache.bigtop.manager.common.enums.JobState;
+import org.apache.bigtop.manager.common.utils.JsonUtils;
 import org.apache.bigtop.manager.dao.po.JobPO;
 import org.apache.bigtop.manager.dao.po.StagePO;
 import org.apache.bigtop.manager.dao.po.TaskPO;
 import org.apache.bigtop.manager.dao.repository.JobRepository;
 import org.apache.bigtop.manager.dao.repository.StageRepository;
 import org.apache.bigtop.manager.dao.repository.TaskRepository;
+import org.apache.bigtop.manager.server.command.CommandIdentifier;
+import org.apache.bigtop.manager.server.command.factory.JobFactories;
+import org.apache.bigtop.manager.server.command.factory.JobFactory;
+import org.apache.bigtop.manager.server.command.job.Job;
+import org.apache.bigtop.manager.server.command.job.JobContext;
 import org.apache.bigtop.manager.server.command.scheduler.JobScheduler;
+import org.apache.bigtop.manager.server.command.stage.Stage;
+import org.apache.bigtop.manager.server.command.task.Task;
 import org.apache.bigtop.manager.server.enums.ApiExceptionEnum;
 import org.apache.bigtop.manager.server.exception.ApiException;
 import org.apache.bigtop.manager.server.model.converter.JobConverter;
@@ -42,6 +50,7 @@ import org.springframework.data.domain.Pageable;
 import org.springframework.stereotype.Service;
 
 import jakarta.annotation.Resource;
+import java.util.List;
 
 @Service
 public class JobServiceImpl implements JobService {
@@ -85,6 +94,14 @@ public class JobServiceImpl implements JobService {
             throw new ApiException(ApiExceptionEnum.JOB_NOT_RETRYABLE);
         }
 
+        resetJobStatusInDB(jobPO);
+        Job job = recreateJob(jobPO);
+        jobScheduler.submit(job);
+
+        return JobConverter.INSTANCE.fromPO2VO(jobPO);
+    }
+
+    private void resetJobStatusInDB(JobPO jobPO) {
         for (StagePO stagePO : jobPO.getStagePOList()) {
             for (TaskPO taskPO : stagePO.getTaskPOList()) {
                 taskPO.setState(JobState.PENDING);
@@ -97,8 +114,58 @@ public class JobServiceImpl implements JobService {
 
         jobPO.setState(JobState.PENDING);
         jobRepository.save(jobPO);
-        jobScheduler.submit(jobPO);
+    }
 
-        return JobConverter.INSTANCE.fromPO2VO(jobPO);
+    private Job recreateJob(JobPO jobPO) {
+        JobContext jobContext = JsonUtils.readFromString(jobPO.getContext(), JobContext.class);
+        CommandIdentifier commandIdentifier = new CommandIdentifier(
+                jobContext.getCommandDTO().getCommandLevel(),
+                jobContext.getCommandDTO().getCommand());
+        JobFactory jobFactory = JobFactories.getJobFactory(commandIdentifier);
+        Job job = jobFactory.createJob(jobContext);
+
+        job.loadJobPO(jobPO);
+        for (int i = 0; i < job.getStages().size(); i++) {
+            Stage stage = job.getStages().get(i);
+            StagePO stagePO = findCorrectStagePO(jobPO.getStagePOList(), i + 1);
+            if (stagePO == null) {
+                throw new ApiException(ApiExceptionEnum.JOB_NOT_RETRYABLE);
+            }
+
+            stage.loadStagePO(stagePO);
+
+            for (int j = 0; j < stage.getTasks().size(); j++) {
+                Task task = stage.getTasks().get(j);
+                TaskPO taskPO = findCorrectTaskPO(
+                        stagePO.getTaskPOList(), task.getTaskContext().getHostname());
+                if (taskPO == null) {
+                    throw new ApiException(ApiExceptionEnum.JOB_NOT_RETRYABLE);
+                }
+
+                task.loadTaskPO(taskPO);
+            }
+        }
+
+        return job;
+    }
+
+    private StagePO findCorrectStagePO(List<StagePO> stagePOList, Integer order) {
+        for (StagePO stagePO : stagePOList) {
+            if (stagePO.getOrder().equals(order)) {
+                return stagePO;
+            }
+        }
+
+        return null;
+    }
+
+    private TaskPO findCorrectTaskPO(List<TaskPO> taskPOList, String hostname) {
+        for (TaskPO taskPO : taskPOList) {
+            if (taskPO.getHostname().equals(hostname)) {
+                return taskPO;
+            }
+        }
+
+        return null;
     }
 }
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/ServiceServiceImpl.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/ServiceServiceImpl.java
index 30889a0..e3643be 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/ServiceServiceImpl.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/ServiceServiceImpl.java
@@ -42,6 +42,8 @@ import org.apache.bigtop.manager.server.service.ServiceService;
 
 import org.apache.commons.lang3.StringUtils;
 
+import org.springframework.stereotype.Service;
+
 import lombok.extern.slf4j.Slf4j;
 
 import jakarta.annotation.Resource;
@@ -51,7 +53,7 @@ import java.util.Map;
 import java.util.stream.Collectors;
 
 @Slf4j
-@org.springframework.stereotype.Service
+@Service
 public class ServiceServiceImpl implements ServiceService {
 
     @Resource
diff --git a/bigtop-manager-server/src/main/resources/ddl/MySQL-DDL-CREATE.sql b/bigtop-manager-server/src/main/resources/ddl/MySQL-DDL-CREATE.sql
index a2f16cf..3d9460b 100644
--- a/bigtop-manager-server/src/main/resources/ddl/MySQL-DDL-CREATE.sql
+++ b/bigtop-manager-server/src/main/resources/ddl/MySQL-DDL-CREATE.sql
@@ -198,15 +198,13 @@ CREATE TABLE `task`
 (
     `id`              BIGINT NOT NULL,
     `command`         VARCHAR(255),
-    `command_script`  VARCHAR(255),
     `component_name`  VARCHAR(255),
     `content`         LONGTEXT,
+    `context`         LONGTEXT NOT NULL,
     `create_by`       BIGINT,
     `create_time`     DATETIME,
     `custom_command`  VARCHAR(255),
-    `custom_commands` LONGTEXT,
     `hostname`        VARCHAR(255),
-    `message_id`      VARCHAR(255),
     `name`            VARCHAR(255),
     `service_group`   VARCHAR(255),
     `service_name`    VARCHAR(255),
diff --git a/bigtop-manager-stack/bigtop-manager-stack-core/src/main/java/org/apache/bigtop/manager/stack/core/executor/StackExecutor.java b/bigtop-manager-stack/bigtop-manager-stack-core/src/main/java/org/apache/bigtop/manager/stack/core/executor/StackExecutor.java
index 55da1ca..33d54b9 100644
--- a/bigtop-manager-stack/bigtop-manager-stack-core/src/main/java/org/apache/bigtop/manager/stack/core/executor/StackExecutor.java
+++ b/bigtop-manager-stack/bigtop-manager-stack-core/src/main/java/org/apache/bigtop/manager/stack/core/executor/StackExecutor.java
@@ -110,7 +110,7 @@ public class StackExecutor {
 
             return result;
         } catch (Exception e) {
-            log.info("Error executing command, payload: {}", commandPayload, e);
+            log.error("Error executing command, payload: {}", commandPayload, e);
             return ShellResult.fail();
         }
     }
diff --git a/bigtop-manager-ui/src/components/service-add/choose-services.vue b/bigtop-manager-ui/src/components/service-add/choose-services.vue
index b116135..93251c8 100644
--- a/bigtop-manager-ui/src/components/service-add/choose-services.vue
+++ b/bigtop-manager-ui/src/components/service-add/choose-services.vue
@@ -26,7 +26,7 @@
   import { ServiceVO } from '@/api/service/types.ts'
   import { useStackStore } from '@/store/stack'
   import { ComponentVO, ServiceComponentVO } from '@/api/component/types.ts'
-  import { TypeConfigVO, ServiceConfigVO } from '@/api/config/types.ts'
+  import { ServiceConfigVO, TypeConfigVO } from '@/api/config/types.ts'
   import _ from 'lodash'
 
   const serviceInfo = defineModel<any>('serviceInfo')
@@ -84,6 +84,7 @@
 
     return {
       serviceName: serviceName,
+      installed: false,
       componentHosts: componentHosts,
       configs: configs
     }
diff --git a/bigtop-manager-ui/src/components/service-add/index.vue b/bigtop-manager-ui/src/components/service-add/index.vue
index 496d599..8bcc063 100644
--- a/bigtop-manager-ui/src/components/service-add/index.vue
+++ b/bigtop-manager-ui/src/components/service-add/index.vue
@@ -117,6 +117,7 @@
 
       return {
         serviceName: serviceName,
+        installed: true,
         componentHosts: componentHosts,
         configs: configs
       }