You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by me...@apache.org on 2020/08/03 07:24:53 UTC
[shardingsphere-elasticjob-ui] branch master updated: Remove cloud
scheduler dependency
This is an automated email from the ASF dual-hosted git repository.
menghaoran pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere-elasticjob-ui.git
The following commit(s) were added to refs/heads/master by this push:
new 4936142 Remove cloud scheduler dependency
new eae31a2 Merge pull request #33 from menghaoranss/dev0731
4936142 is described below
commit 49361425af308858ce70ac5615fd84780df2f0a7
Author: menghaoranss <lo...@163.com>
AuthorDate: Mon Aug 3 15:21:40 2020 +0800
Remove cloud scheduler dependency
---
pom.xml | 6 +
.../pom.xml | 6 +-
.../cloud/ui/config/BeanConfiguration.java | 108 +-----
.../cloud/ui/config/EventTraceConfiguration.java | 55 +++
.../cloud/ui/config/JobStateConfiguration.java | 32 ++
.../cloud/ui/config/RegistryConfiguration.java | 44 +++
.../ui/exception/AppConfigurationException.java | 30 ++
.../ui/repository/StatisticRdbRepository.java | 402 +++++++++++++++++++++
.../elasticjob/cloud/ui/service/FacadeService.java | 309 ++++++++++++++++
.../cloud/ui/service/RegistryCenterFactory.java | 2 +
.../ui/service/app/CloudAppConfiguration.java | 47 +++
.../ui/service/app/CloudAppConfigurationNode.java | 36 ++
.../service/app/CloudAppConfigurationService.java | 98 +++++
.../app/pojo/CloudAppConfigurationPOJO.java | 71 ++++
.../ui/service/job/CloudJobConfigurationNode.java | 36 ++
.../service/job/CloudJobConfigurationService.java | 98 +++++
.../cloud/ui/service/producer/ProducerManager.java | 94 +++++
.../cloud/ui/service/state/StateNode.java | 33 ++
.../service/state/disable/app/DisableAppNode.java | 37 ++
.../state/disable/app/DisableAppService.java | 73 ++++
.../service/state/disable/job/DisableJobNode.java | 37 ++
.../state/disable/job/DisableJobService.java | 73 ++++
.../ui/service/state/failover/FailoverNode.java | 44 +++
.../ui/service/state/failover/FailoverService.java | 146 ++++++++
.../service/state/failover/FailoverTaskInfo.java | 34 ++
.../cloud/ui/service/state/ready/ReadyNode.java | 37 ++
.../cloud/ui/service/state/ready/ReadyService.java | 147 ++++++++
.../ui/service/state/running/RunningNode.java | 44 +++
.../ui/service/state/running/RunningService.java | 253 +++++++++++++
.../ui/service/statistics/StatisticManager.java | 171 +++++++++
.../ui/service/statistics/TaskResultMetaData.java | 79 ++++
.../statistics/util/StatisticTimeUtils.java | 71 ++++
.../ui/web/controller/CloudAppController.java | 55 +--
.../ui/web/controller/CloudJobController.java | 16 +-
.../web/controller/CloudOperationController.java | 94 -----
.../src/main/resources/application.properties | 22 ++
.../conf/elasticjob-cloud-scheduler.properties | 62 ----
.../src/main/resources/application.properties | 20 +
.../elasticjob-cloud-scheduler.properties | 62 ----
39 files changed, 2716 insertions(+), 368 deletions(-)
diff --git a/pom.xml b/pom.xml
index 749d7f4..9c2d101 100644
--- a/pom.xml
+++ b/pom.xml
@@ -51,6 +51,7 @@
<commons-dbcp2.version>2.2.0</commons-dbcp2.version>
<h2.version>1.4.196</h2.version>
<lombok.version>1.16.20</lombok.version>
+ <commons.codec.version>1.10</commons.codec.version>
<maven.deploy.skip>true</maven.deploy.skip>
</properties>
@@ -179,6 +180,11 @@
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>commons-codec</groupId>
+ <artifactId>commons-codec</artifactId>
+ <version>${commons.codec.version}</version>
+ </dependency>
</dependencies>
</dependencyManagement>
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/pom.xml b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/pom.xml
index 6911e2b..d500bd5 100644
--- a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/pom.xml
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/pom.xml
@@ -29,7 +29,7 @@
<dependencies>
<dependency>
<groupId>org.apache.shardingsphere.elasticjob</groupId>
- <artifactId>elasticjob-cloud-scheduler</artifactId>
+ <artifactId>elasticjob-cloud-common</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
@@ -68,6 +68,10 @@
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
+ <dependency>
+ <groupId>commons-codec</groupId>
+ <artifactId>commons-codec</artifactId>
+ </dependency>
</dependencies>
<build>
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/config/BeanConfiguration.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/config/BeanConfiguration.java
index 10f2386..95e7571 100644
--- a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/config/BeanConfiguration.java
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/config/BeanConfiguration.java
@@ -17,28 +17,13 @@
package org.apache.shardingsphere.elasticjob.cloud.ui.config;
-import com.netflix.fenzo.TaskScheduler;
import lombok.extern.slf4j.Slf4j;
-import org.apache.mesos.MesosSchedulerDriver;
-import org.apache.mesos.Protos;
-import org.apache.mesos.SchedulerDriver;
-import org.apache.shardingsphere.elasticjob.cloud.scheduler.config.app.CloudAppConfigurationService;
-import org.apache.shardingsphere.elasticjob.cloud.scheduler.config.job.CloudJobConfigurationService;
-import org.apache.shardingsphere.elasticjob.cloud.scheduler.env.BootstrapEnvironment;
-import org.apache.shardingsphere.elasticjob.cloud.scheduler.env.MesosConfiguration;
-import org.apache.shardingsphere.elasticjob.cloud.scheduler.ha.FrameworkIDService;
-import org.apache.shardingsphere.elasticjob.cloud.scheduler.mesos.FacadeService;
-import org.apache.shardingsphere.elasticjob.cloud.scheduler.mesos.MesosStateService;
-import org.apache.shardingsphere.elasticjob.cloud.scheduler.mesos.ReconcileService;
-import org.apache.shardingsphere.elasticjob.cloud.scheduler.mesos.SchedulerEngine;
-import org.apache.shardingsphere.elasticjob.cloud.scheduler.producer.ProducerManager;
-import org.apache.shardingsphere.elasticjob.cloud.scheduler.state.disable.app.DisableAppService;
-import org.apache.shardingsphere.elasticjob.cloud.scheduler.statistics.StatisticManager;
+import org.apache.shardingsphere.elasticjob.cloud.ui.repository.StatisticRdbRepository;
import org.apache.shardingsphere.elasticjob.cloud.ui.web.controller.search.JobEventRdbSearch;
import org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;
import org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter;
-import org.apache.shardingsphere.elasticjob.tracing.JobEventBus;
import org.apache.shardingsphere.elasticjob.tracing.api.TracingConfiguration;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -49,97 +34,28 @@ import java.util.Optional;
@Slf4j
public class BeanConfiguration {
- private static final String WEB_UI_PROTOCOL = "http://";
+ @Autowired
+ private EventTraceConfiguration traceConfiguration;
+
+ @Autowired
+ private RegistryConfiguration registryConfiguration;
@Bean
public CoordinatorRegistryCenter regCenter() {
- CoordinatorRegistryCenter registryCenter = new ZookeeperRegistryCenter(BootstrapEnvironment.getINSTANCE().getZookeeperConfiguration());
+ CoordinatorRegistryCenter registryCenter = new ZookeeperRegistryCenter(registryConfiguration.getZookeeperConfiguration());
registryCenter.init();
return registryCenter;
}
@Bean
- public CloudAppConfigurationService appConfigService() {
- return new CloudAppConfigurationService(regCenter());
- }
-
- @Bean
- public CloudJobConfigurationService jobConfigService() {
- return new CloudJobConfigurationService(regCenter());
- }
-
- @Bean
- public MesosStateService mesosStateService() {
- return new MesosStateService(regCenter());
- }
-
- @Bean
- public DisableAppService disableAppService() {
- return new DisableAppService(regCenter());
- }
-
- @Bean
- public ProducerManager producerManager() {
- return new ProducerManager(schedulerDriver(), regCenter());
- }
-
- @Bean
- public FacadeService facadeService() {
- return new FacadeService(regCenter());
- }
-
- @Bean
- public StatisticManager statisticManager() {
- return StatisticManager.getInstance(regCenter(), BootstrapEnvironment.getINSTANCE().getTracingConfiguration().orElse(null));
- }
-
- @Bean
- public FrameworkIDService frameworkIDService() {
- return new FrameworkIDService(regCenter());
- }
-
- @Bean
- public TaskScheduler taskScheduler() {
- return new TaskScheduler.Builder()
- .withLeaseOfferExpirySecs(1000000000L)
- .withLeaseRejectAction(lease -> {
- log.warn("Declining offer on '{}'", lease.hostname());
- schedulerDriver().declineOffer(lease.getOffer().getId());
- }).build();
- }
-
- @Bean
- public JobEventBus jobEventBus() {
- Optional<TracingConfiguration> tracingConfiguration = BootstrapEnvironment.getINSTANCE().getTracingConfiguration();
- return tracingConfiguration.map(JobEventBus::new).orElseGet(JobEventBus::new);
- }
-
- @Bean
- public SchedulerDriver schedulerDriver() {
- Protos.FrameworkInfo.Builder builder = Protos.FrameworkInfo.newBuilder();
- frameworkIDService().fetch().ifPresent(frameworkID -> builder.setId(Protos.FrameworkID.newBuilder().setValue(frameworkID).build()));
- Optional<String> role = BootstrapEnvironment.getINSTANCE().getMesosRole();
- String frameworkName = MesosConfiguration.FRAMEWORK_NAME;
- if (role.isPresent()) {
- builder.setRole(role.get());
- frameworkName += "-" + role.get();
- }
- builder.addCapabilitiesBuilder().setType(Protos.FrameworkInfo.Capability.Type.PARTITION_AWARE);
- MesosConfiguration mesosConfig = BootstrapEnvironment.getINSTANCE().getMesosConfiguration();
- Protos.FrameworkInfo frameworkInfo = builder.setUser(mesosConfig.getUser()).setName(frameworkName)
- .setHostname(mesosConfig.getHostname()).setFailoverTimeout(MesosConfiguration.FRAMEWORK_FAILOVER_TIMEOUT_SECONDS)
- .setWebuiUrl(WEB_UI_PROTOCOL + BootstrapEnvironment.getINSTANCE().getFrameworkHostPort()).setCheckpoint(true).build();
- return new MesosSchedulerDriver(new SchedulerEngine(taskScheduler(), facadeService(), jobEventBus(), frameworkIDService(), statisticManager()), frameworkInfo, mesosConfig.getUrl());
+ public StatisticRdbRepository rdbRepository() {
+ Optional<TracingConfiguration> tracingConfiguration = traceConfiguration.getTracingConfiguration();
+ return tracingConfiguration.map(each -> new StatisticRdbRepository((DataSource) each.getStorage(), true)).orElse(new StatisticRdbRepository(null, false));
}
@Bean
public JobEventRdbSearch jobEventRdbSearch() {
- Optional<TracingConfiguration> tracingConfiguration = BootstrapEnvironment.getINSTANCE().getTracingConfiguration();
+ Optional<TracingConfiguration> tracingConfiguration = traceConfiguration.getTracingConfiguration();
return tracingConfiguration.map(each -> new JobEventRdbSearch((DataSource) each.getStorage(), true)).orElse(new JobEventRdbSearch(null, false));
}
-
- @Bean
- public ReconcileService reconcileService() {
- return new ReconcileService(schedulerDriver(), facadeService());
- }
}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/config/EventTraceConfiguration.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/config/EventTraceConfiguration.java
new file mode 100644
index 0000000..c0aabe2
--- /dev/null
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/config/EventTraceConfiguration.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.cloud.ui.config;
+
+import com.google.common.base.Strings;
+import lombok.Setter;
+import org.apache.commons.dbcp.BasicDataSource;
+import org.apache.shardingsphere.elasticjob.tracing.api.TracingConfiguration;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+import javax.sql.DataSource;
+import java.util.Optional;
+
+@Component
+@ConfigurationProperties(prefix = "event.trace")
+@Setter
+public final class EventTraceConfiguration {
+
+ private String rdbDriver;
+
+ private String rdbUrl;
+
+ private String rdbUsername;
+
+ private String rdbPassword;
+
+ public Optional<TracingConfiguration> getTracingConfiguration() {
+
+ if (!Strings.isNullOrEmpty(rdbDriver) && !Strings.isNullOrEmpty(rdbUrl) && !Strings.isNullOrEmpty(rdbUsername)) {
+ BasicDataSource dataSource = new BasicDataSource();
+ dataSource.setDriverClassName(rdbDriver);
+ dataSource.setUrl(rdbUrl);
+ dataSource.setUsername(rdbUsername);
+ dataSource.setPassword(rdbPassword);
+ return Optional.of(new TracingConfiguration<DataSource>("RDB", dataSource));
+ }
+ return Optional.empty();
+ }
+}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/config/JobStateConfiguration.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/config/JobStateConfiguration.java
new file mode 100644
index 0000000..ddc9abb
--- /dev/null
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/config/JobStateConfiguration.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.cloud.ui.config;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Component
+@ConfigurationProperties(prefix = "job.state")
+@Getter
+@Setter
+public final class JobStateConfiguration {
+
+ private int queueSize = 10000;
+}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/config/RegistryConfiguration.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/config/RegistryConfiguration.java
new file mode 100644
index 0000000..64af62a
--- /dev/null
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/config/RegistryConfiguration.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.cloud.ui.config;
+
+import com.google.common.base.Strings;
+import lombok.Setter;
+import org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperConfiguration;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Component
+@ConfigurationProperties(prefix = "zk")
+@Setter
+public final class RegistryConfiguration {
+
+ private String servers;
+
+ private String namespace;
+
+ private String digest;
+
+ public ZookeeperConfiguration getZookeeperConfiguration() {
+ ZookeeperConfiguration result = new ZookeeperConfiguration(servers, namespace);
+ if (!Strings.isNullOrEmpty(digest)) {
+ result.setDigest(digest);
+ }
+ return result;
+ }
+}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/exception/AppConfigurationException.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/exception/AppConfigurationException.java
new file mode 100644
index 0000000..3fc624f
--- /dev/null
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/exception/AppConfigurationException.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.cloud.ui.exception;
+
+/**
+ * Application configuration exception.
+ */
+public final class AppConfigurationException extends RuntimeException {
+
+ private static final long serialVersionUID = -1466479389299512371L;
+
+ public AppConfigurationException(final String errorMessage, final Object... args) {
+ super(String.format(errorMessage, args));
+ }
+}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/repository/StatisticRdbRepository.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/repository/StatisticRdbRepository.java
new file mode 100644
index 0000000..9c1fc96
--- /dev/null
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/repository/StatisticRdbRepository.java
@@ -0,0 +1,402 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.cloud.ui.repository;
+
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shardingsphere.elasticjob.cloud.statistics.StatisticInterval;
+import org.apache.shardingsphere.elasticjob.cloud.statistics.type.job.JobRegisterStatistics;
+import org.apache.shardingsphere.elasticjob.cloud.statistics.type.job.JobRunningStatistics;
+import org.apache.shardingsphere.elasticjob.cloud.statistics.type.task.TaskResultStatistics;
+import org.apache.shardingsphere.elasticjob.cloud.statistics.type.task.TaskRunningStatistics;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * Statistic RDB repository.
+ */
+@Slf4j
+public class StatisticRdbRepository {
+
+ private static final String TABLE_TASK_RESULT_STATISTICS = "TASK_RESULT_STATISTICS";
+
+ private static final String TABLE_TASK_RUNNING_STATISTICS = "TASK_RUNNING_STATISTICS";
+
+ private static final String TABLE_JOB_RUNNING_STATISTICS = "JOB_RUNNING_STATISTICS";
+
+ private static final String TABLE_JOB_REGISTER_STATISTICS = "JOB_REGISTER_STATISTICS";
+
+ private final DataSource dataSource;
+
+ @Getter
+ private final boolean enable;
+
+ public StatisticRdbRepository(final DataSource dataSource, final boolean enable) {
+ this.dataSource = dataSource;
+ this.enable = enable;
+ }
+
+ /**
+ * Add task result statistics.
+ *
+ * @param taskResultStatistics task result statistics
+ * @return add success or not
+ */
+ public boolean add(final TaskResultStatistics taskResultStatistics) {
+ boolean result = false;
+ String sql = "INSERT INTO `" + TABLE_TASK_RESULT_STATISTICS + "_" + taskResultStatistics.getStatisticInterval()
+ + "` (`success_count`, `failed_count`, `statistics_time`, `creation_time`) VALUES (?, ?, ?, ?);";
+ try (
+ Connection conn = dataSource.getConnection();
+ PreparedStatement preparedStatement = conn.prepareStatement(sql)) {
+ preparedStatement.setInt(1, taskResultStatistics.getSuccessCount());
+ preparedStatement.setInt(2, taskResultStatistics.getFailedCount());
+ preparedStatement.setTimestamp(3, new Timestamp(taskResultStatistics.getStatisticsTime().getTime()));
+ preparedStatement.setTimestamp(4, new Timestamp(taskResultStatistics.getCreationTime().getTime()));
+ preparedStatement.execute();
+ result = true;
+ } catch (final SQLException ex) {
+ // TODO log failure directly to output log, consider to be configurable in the future
+ log.error("Insert taskResultStatistics to DB error:", ex);
+ }
+ return result;
+ }
+
+ /**
+ * Add task running statistics.
+ *
+ * @param taskRunningStatistics task running statistics
+ * @return add success or not
+ */
+ public boolean add(final TaskRunningStatistics taskRunningStatistics) {
+ boolean result = false;
+ String sql = "INSERT INTO `" + TABLE_TASK_RUNNING_STATISTICS + "` (`running_count`, `statistics_time`, `creation_time`) VALUES (?, ?, ?);";
+ try (
+ Connection conn = dataSource.getConnection();
+ PreparedStatement preparedStatement = conn.prepareStatement(sql)) {
+ preparedStatement.setInt(1, taskRunningStatistics.getRunningCount());
+ preparedStatement.setTimestamp(2, new Timestamp(taskRunningStatistics.getStatisticsTime().getTime()));
+ preparedStatement.setTimestamp(3, new Timestamp(taskRunningStatistics.getCreationTime().getTime()));
+ preparedStatement.execute();
+ result = true;
+ } catch (final SQLException ex) {
+ // TODO log failure directly to output log, consider to be configurable in the future
+ log.error("Insert taskRunningStatistics to DB error:", ex);
+ }
+ return result;
+ }
+
+ /**
+ * Add job running statistics.
+ *
+ * @param jobRunningStatistics job running statistics
+ * @return add success or not
+ */
+ public boolean add(final JobRunningStatistics jobRunningStatistics) {
+ boolean result = false;
+ String sql = "INSERT INTO `" + TABLE_JOB_RUNNING_STATISTICS + "` (`running_count`, `statistics_time`, `creation_time`) VALUES (?, ?, ?);";
+ try (
+ Connection conn = dataSource.getConnection();
+ PreparedStatement preparedStatement = conn.prepareStatement(sql)) {
+ preparedStatement.setInt(1, jobRunningStatistics.getRunningCount());
+ preparedStatement.setTimestamp(2, new Timestamp(jobRunningStatistics.getStatisticsTime().getTime()));
+ preparedStatement.setTimestamp(3, new Timestamp(jobRunningStatistics.getCreationTime().getTime()));
+ preparedStatement.execute();
+ result = true;
+ } catch (final SQLException ex) {
+ // TODO log failure directly to output log, consider to be configurable in the future
+ log.error("Insert jobRunningStatistics to DB error:", ex);
+ }
+ return result;
+ }
+
+ /**
+ * Add job register statistics.
+ *
+ * @param jobRegisterStatistics job register statistics
+ * @return add success or not
+ */
+ public boolean add(final JobRegisterStatistics jobRegisterStatistics) {
+ boolean result = false;
+ String sql = "INSERT INTO `" + TABLE_JOB_REGISTER_STATISTICS + "` (`registered_count`, `statistics_time`, `creation_time`) VALUES (?, ?, ?);";
+ try (
+ Connection conn = dataSource.getConnection();
+ PreparedStatement preparedStatement = conn.prepareStatement(sql)) {
+ preparedStatement.setInt(1, jobRegisterStatistics.getRegisteredCount());
+ preparedStatement.setTimestamp(2, new Timestamp(jobRegisterStatistics.getStatisticsTime().getTime()));
+ preparedStatement.setTimestamp(3, new Timestamp(jobRegisterStatistics.getCreationTime().getTime()));
+ preparedStatement.execute();
+ result = true;
+ } catch (final SQLException ex) {
+ // TODO log failure directly to output log, consider to be configurable in the future
+ log.error("Insert jobRegisterStatistics to DB error:", ex);
+ }
+ return result;
+ }
+
+ /**
+ * Find task result statistics.
+ *
+ * @param from from date to statistics
+ * @param statisticInterval statistic interval
+ * @return task result statistics
+ */
+ public List<TaskResultStatistics> findTaskResultStatistics(final Date from, final StatisticInterval statisticInterval) {
+ List<TaskResultStatistics> result = new LinkedList<>();
+ SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ String sql = String.format("SELECT id, success_count, failed_count, statistics_time, creation_time FROM %s WHERE statistics_time >= '%s' order by id ASC",
+ TABLE_TASK_RESULT_STATISTICS + "_" + statisticInterval, formatter.format(from));
+ try (
+ Connection conn = dataSource.getConnection();
+ PreparedStatement preparedStatement = conn.prepareStatement(sql);
+ ResultSet resultSet = preparedStatement.executeQuery()
+ ) {
+ while (resultSet.next()) {
+ TaskResultStatistics taskResultStatistics = new TaskResultStatistics(resultSet.getLong(1), resultSet.getInt(2), resultSet.getInt(3),
+ statisticInterval, new Date(resultSet.getTimestamp(4).getTime()), new Date(resultSet.getTimestamp(5).getTime()));
+ result.add(taskResultStatistics);
+ }
+ } catch (final SQLException ex) {
+ // TODO log failure directly to output log, consider to be configurable in the future
+ log.error("Fetch taskResultStatistics from DB error:", ex);
+ }
+ return result;
+ }
+
+ /**
+ * Get summed task result statistics.
+ *
+ * @param from from date to statistics
+ * @param statisticInterval statistic interval
+ * @return summed task result statistics
+ */
+ public TaskResultStatistics getSummedTaskResultStatistics(final Date from, final StatisticInterval statisticInterval) {
+ TaskResultStatistics result = new TaskResultStatistics(0, 0, statisticInterval, new Date());
+ SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ String sql = String.format("SELECT sum(success_count), sum(failed_count) FROM %s WHERE statistics_time >= '%s'",
+ TABLE_TASK_RESULT_STATISTICS + "_" + statisticInterval, formatter.format(from));
+ try (
+ Connection conn = dataSource.getConnection();
+ PreparedStatement preparedStatement = conn.prepareStatement(sql);
+ ResultSet resultSet = preparedStatement.executeQuery()
+ ) {
+ while (resultSet.next()) {
+ result = new TaskResultStatistics(resultSet.getInt(1), resultSet.getInt(2), statisticInterval, new Date());
+ }
+ } catch (final SQLException ex) {
+ // TODO log failure directly to output log, consider to be configurable in the future
+ log.error("Fetch summed taskResultStatistics from DB error:", ex);
+ }
+ return result;
+ }
+
+ /**
+ * Find latest task result statistics.
+ *
+ * @param statisticInterval statistic interval
+ * @return task result statistics
+ */
+ public Optional<TaskResultStatistics> findLatestTaskResultStatistics(final StatisticInterval statisticInterval) {
+ TaskResultStatistics result = null;
+ String sql = String.format("SELECT id, success_count, failed_count, statistics_time, creation_time FROM %s order by id DESC LIMIT 1",
+ TABLE_TASK_RESULT_STATISTICS + "_" + statisticInterval);
+ try (
+ Connection conn = dataSource.getConnection();
+ PreparedStatement preparedStatement = conn.prepareStatement(sql);
+ ResultSet resultSet = preparedStatement.executeQuery()
+ ) {
+ while (resultSet.next()) {
+ result = new TaskResultStatistics(resultSet.getLong(1), resultSet.getInt(2), resultSet.getInt(3),
+ statisticInterval, new Date(resultSet.getTimestamp(4).getTime()), new Date(resultSet.getTimestamp(5).getTime()));
+ }
+ } catch (final SQLException ex) {
+ // TODO log failure directly to output log, consider to be configurable in the future
+ log.error("Fetch latest taskResultStatistics from DB error:", ex);
+ }
+ return Optional.ofNullable(result);
+ }
+
+ /**
+ * Find task running statistics.
+ *
+ * @param from from date to statistics
+ * @return Task running statistics
+ */
+ public List<TaskRunningStatistics> findTaskRunningStatistics(final Date from) {
+ List<TaskRunningStatistics> result = new LinkedList<>();
+ SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ String sql = String.format("SELECT id, running_count, statistics_time, creation_time FROM %s WHERE statistics_time >= '%s' order by id ASC",
+ TABLE_TASK_RUNNING_STATISTICS, formatter.format(from));
+ try (
+ Connection conn = dataSource.getConnection();
+ PreparedStatement preparedStatement = conn.prepareStatement(sql);
+ ResultSet resultSet = preparedStatement.executeQuery()
+ ) {
+ while (resultSet.next()) {
+ TaskRunningStatistics taskRunningStatistics = new TaskRunningStatistics(resultSet.getLong(1), resultSet.getInt(2),
+ new Date(resultSet.getTimestamp(3).getTime()), new Date(resultSet.getTimestamp(4).getTime()));
+ result.add(taskRunningStatistics);
+ }
+ } catch (final SQLException ex) {
+ // TODO log failure directly to output log, consider to be configurable in the future
+ log.error("Fetch taskRunningStatistics from DB error:", ex);
+ }
+ return result;
+ }
+
+ /**
+ * Find job running statistics.
+ *
+ * @param from from date to statistics
+ * @return job running statistics
+ */
+ public List<JobRunningStatistics> findJobRunningStatistics(final Date from) {
+ List<JobRunningStatistics> result = new LinkedList<>();
+ SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ String sql = String.format("SELECT id, running_count, statistics_time, creation_time FROM %s WHERE statistics_time >= '%s' order by id ASC",
+ TABLE_JOB_RUNNING_STATISTICS, formatter.format(from));
+ try (
+ Connection conn = dataSource.getConnection();
+ PreparedStatement preparedStatement = conn.prepareStatement(sql);
+ ResultSet resultSet = preparedStatement.executeQuery()
+ ) {
+ while (resultSet.next()) {
+ JobRunningStatistics jobRunningStatistics = new JobRunningStatistics(resultSet.getLong(1), resultSet.getInt(2),
+ new Date(resultSet.getTimestamp(3).getTime()), new Date(resultSet.getTimestamp(4).getTime()));
+ result.add(jobRunningStatistics);
+ }
+ } catch (final SQLException ex) {
+ // TODO log failure directly to output log, consider to be configurable in the future
+ log.error("Fetch jobRunningStatistics from DB error:", ex);
+ }
+ return result;
+ }
+
+ /**
+ * Find latest task running statistics.
+ *
+ * @return latest task running statistics
+ */
+ public Optional<TaskRunningStatistics> findLatestTaskRunningStatistics() {
+ TaskRunningStatistics result = null;
+ String sql = String.format("SELECT id, running_count, statistics_time, creation_time FROM %s order by id DESC LIMIT 1",
+ TABLE_TASK_RUNNING_STATISTICS);
+ try (
+ Connection conn = dataSource.getConnection();
+ PreparedStatement preparedStatement = conn.prepareStatement(sql);
+ ResultSet resultSet = preparedStatement.executeQuery()
+ ) {
+ while (resultSet.next()) {
+ result = new TaskRunningStatistics(resultSet.getLong(1), resultSet.getInt(2),
+ new Date(resultSet.getTimestamp(3).getTime()), new Date(resultSet.getTimestamp(4).getTime()));
+ }
+ } catch (final SQLException ex) {
+ // TODO log failure directly to output log, consider to be configurable in the future
+ log.error("Fetch latest taskRunningStatistics from DB error:", ex);
+ }
+ return Optional.ofNullable(result);
+ }
+
+ /**
+ * Find latest job running statistics.
+ *
+ * @return job running statistics
+ */
+ public Optional<JobRunningStatistics> findLatestJobRunningStatistics() {
+ JobRunningStatistics result = null;
+ String sql = String.format("SELECT id, running_count, statistics_time, creation_time FROM %s order by id DESC LIMIT 1", TABLE_JOB_RUNNING_STATISTICS);
+ try (
+ Connection conn = dataSource.getConnection();
+ PreparedStatement preparedStatement = conn.prepareStatement(sql);
+ ResultSet resultSet = preparedStatement.executeQuery()
+ ) {
+ while (resultSet.next()) {
+ result = new JobRunningStatistics(resultSet.getLong(1), resultSet.getInt(2),
+ new Date(resultSet.getTimestamp(3).getTime()), new Date(resultSet.getTimestamp(4).getTime()));
+ }
+ } catch (final SQLException ex) {
+ // TODO log failure directly to output log, consider to be configurable in the future
+ log.error("Fetch latest jobRunningStatistics from DB error:", ex);
+ }
+ return Optional.ofNullable(result);
+ }
+
+ /**
+ * Find job register statistics.
+ *
+ * @param from from date to statistics
+ * @return job register statistics
+ */
+ public List<JobRegisterStatistics> findJobRegisterStatistics(final Date from) {
+ List<JobRegisterStatistics> result = new LinkedList<>();
+ SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ String sql = String.format("SELECT id, registered_count, statistics_time, creation_time FROM %s WHERE statistics_time >= '%s' order by id ASC",
+ TABLE_JOB_REGISTER_STATISTICS, formatter.format(from));
+ try (
+ Connection conn = dataSource.getConnection();
+ PreparedStatement preparedStatement = conn.prepareStatement(sql);
+ ResultSet resultSet = preparedStatement.executeQuery()
+ ) {
+ while (resultSet.next()) {
+ JobRegisterStatistics jobRegisterStatistics = new JobRegisterStatistics(resultSet.getLong(1), resultSet.getInt(2),
+ new Date(resultSet.getTimestamp(3).getTime()), new Date(resultSet.getTimestamp(4).getTime()));
+ result.add(jobRegisterStatistics);
+ }
+ } catch (final SQLException ex) {
+ // TODO log failure directly to output log, consider to be configurable in the future
+ log.error("Fetch jobRegisterStatistics from DB error:", ex);
+ }
+ return result;
+ }
+
+ /**
+ * Find latest job register statistics.
+ *
+ * @return job register statistics
+ */
+ public Optional<JobRegisterStatistics> findLatestJobRegisterStatistics() {
+ JobRegisterStatistics result = null;
+ String sql = String.format("SELECT id, registered_count, statistics_time, creation_time FROM %s order by id DESC LIMIT 1",
+ TABLE_JOB_REGISTER_STATISTICS);
+ try (
+ Connection conn = dataSource.getConnection();
+ PreparedStatement preparedStatement = conn.prepareStatement(sql);
+ ResultSet resultSet = preparedStatement.executeQuery()
+ ) {
+ while (resultSet.next()) {
+ result = new JobRegisterStatistics(resultSet.getLong(1), resultSet.getInt(2),
+ new Date(resultSet.getTimestamp(3).getTime()), new Date(resultSet.getTimestamp(4).getTime()));
+ }
+ } catch (final SQLException ex) {
+ // TODO log failure directly to output log, consider to be configurable in the future
+ log.error("Fetch latest jobRegisterStatistics from DB error:", ex);
+ }
+ return Optional.ofNullable(result);
+ }
+}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/FacadeService.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/FacadeService.java
new file mode 100644
index 0000000..12cc456
--- /dev/null
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/FacadeService.java
@@ -0,0 +1,309 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.cloud.ui.service;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shardingsphere.elasticjob.cloud.config.CloudJobExecutionType;
+import org.apache.shardingsphere.elasticjob.cloud.config.pojo.CloudJobConfigurationPOJO;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.app.CloudAppConfigurationService;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.app.pojo.CloudAppConfigurationPOJO;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.job.CloudJobConfigurationService;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.state.disable.app.DisableAppService;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.state.disable.job.DisableJobService;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.state.failover.FailoverService;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.state.failover.FailoverTaskInfo;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.state.ready.ReadyService;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.state.running.RunningService;
+import org.apache.shardingsphere.elasticjob.infra.context.ExecutionType;
+import org.apache.shardingsphere.elasticjob.infra.context.TaskContext;
+import org.apache.shardingsphere.elasticjob.infra.context.TaskContext.MetaInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Mesos facade service.
+ */
+@Slf4j
+@Service
+public final class FacadeService {
+
+ @Autowired
+ private CloudAppConfigurationService appConfigService;
+
+ @Autowired
+ private CloudJobConfigurationService jobConfigService;
+
+ @Autowired
+ private ReadyService readyService;
+
+ @Autowired
+ private RunningService runningService;
+
+ @Autowired
+ private FailoverService failoverService;
+
+ @Autowired
+ private DisableAppService disableAppService;
+
+ @Autowired
+ private DisableJobService disableJobService;
+
+ /**
+ * Start facade service.
+ */
+ public void start() {
+ log.info("Elastic Job: Start facade service");
+ runningService.start();
+ }
+
+ /**
+ * Remove launched task from queue.
+ *
+ * @param taskContexts task running contexts
+ */
+ public void removeLaunchTasksFromQueue(final List<TaskContext> taskContexts) {
+ List<TaskContext> failoverTaskContexts = new ArrayList<>(taskContexts.size());
+ Collection<String> readyJobNames = new HashSet<>(taskContexts.size(), 1);
+ for (TaskContext each : taskContexts) {
+ switch (each.getType()) {
+ case FAILOVER:
+ failoverTaskContexts.add(each);
+ break;
+ case READY:
+ readyJobNames.add(each.getMetaInfo().getJobName());
+ break;
+ default:
+ break;
+ }
+ }
+ failoverService.remove(failoverTaskContexts.stream().map(TaskContext::getMetaInfo).collect(Collectors.toList()));
+ readyService.remove(readyJobNames);
+ }
+
+ /**
+ * Add task to running queue.
+ *
+ * @param taskContext task running context
+ */
+ public void addRunning(final TaskContext taskContext) {
+ runningService.add(taskContext);
+ }
+
+ /**
+ * Update daemon task status.
+ *
+ * @param taskContext task running context
+ * @param isIdle set to idle or not
+ */
+ public void updateDaemonStatus(final TaskContext taskContext, final boolean isIdle) {
+ runningService.updateIdle(taskContext, isIdle);
+ }
+
+ /**
+ * Remove task from running queue.
+ *
+ * @param taskContext task running context
+ */
+ public void removeRunning(final TaskContext taskContext) {
+ runningService.remove(taskContext);
+ }
+
+ /**
+ * Record task to failover queue.
+ *
+ * @param taskContext task running context
+ */
+ public void recordFailoverTask(final TaskContext taskContext) {
+ Optional<CloudJobConfigurationPOJO> cloudJobConfigOptional = jobConfigService.load(taskContext.getMetaInfo().getJobName());
+ if (!cloudJobConfigOptional.isPresent()) {
+ return;
+ }
+ if (isDisable(cloudJobConfigOptional.get())) {
+ return;
+ }
+ CloudJobConfigurationPOJO cloudJobConfig = cloudJobConfigOptional.get();
+ if (cloudJobConfig.isFailover() || CloudJobExecutionType.DAEMON == cloudJobConfig.getJobExecutionType()) {
+ failoverService.add(taskContext);
+ }
+ }
+
+ private boolean isDisable(final CloudJobConfigurationPOJO cloudJobConfig) {
+ return disableAppService.isDisabled(cloudJobConfig.getAppName()) || disableJobService.isDisabled(cloudJobConfig.getJobName());
+ }
+
+ /**
+ * Add transient job to ready queue.
+ *
+ * @param jobName job name
+ */
+ public void addTransient(final String jobName) {
+ readyService.addTransient(jobName);
+ }
+
+ /**
+ * Load cloud job config.
+ *
+ * @param jobName job name
+ * @return cloud job config
+ */
+ public Optional<CloudJobConfigurationPOJO> load(final String jobName) {
+ return jobConfigService.load(jobName);
+ }
+
+ /**
+ * Load app config by app name.
+ *
+ * @param appName app name
+ * @return cloud app config
+ */
+ public Optional<CloudAppConfigurationPOJO> loadAppConfig(final String appName) {
+ return appConfigService.load(appName);
+ }
+
+ /**
+ * Get failover task id by task meta info.
+ *
+ * @param metaInfo task meta info
+ * @return failover task id
+ */
+ public Optional<String> getFailoverTaskId(final MetaInfo metaInfo) {
+ return failoverService.getTaskId(metaInfo);
+ }
+
+ /**
+ * Add daemon job to ready queue.
+ *
+ * @param jobName job name
+ */
+ public void addDaemonJobToReadyQueue(final String jobName) {
+ Optional<CloudJobConfigurationPOJO> cloudJobConfig = jobConfigService.load(jobName);
+ if (!cloudJobConfig.isPresent()) {
+ return;
+ }
+ if (isDisable(cloudJobConfig.get())) {
+ return;
+ }
+ readyService.addDaemon(jobName);
+ }
+
+ /**
+ * Determine whether the task is running or not.
+ *
+ * @param taskContext task running context
+ * @return true is running, otherwise not
+ */
+ public boolean isRunning(final TaskContext taskContext) {
+ return ExecutionType.FAILOVER != taskContext.getType() && !runningService.getRunningTasks(taskContext.getMetaInfo().getJobName()).isEmpty()
+ || ExecutionType.FAILOVER == taskContext.getType() && runningService.isTaskRunning(taskContext.getMetaInfo());
+ }
+
+ /**
+ * Add mapping of the task primary key and host name.
+ *
+ * @param taskId task primary key
+ * @param hostname host name
+ */
+ public void addMapping(final String taskId, final String hostname) {
+ runningService.addMapping(taskId, hostname);
+ }
+
+ /**
+ * Retrieve hostname and then remove task.
+ *
+ * @param taskId task primary key
+ * @return hostname of the removed task
+ */
+ public String popMapping(final String taskId) {
+ return runningService.popMapping(taskId);
+ }
+
+ /**
+ * Get all ready tasks.
+ *
+ * @return ready tasks
+ */
+ public Map<String, Integer> getAllReadyTasks() {
+ return readyService.getAllReadyTasks();
+ }
+
+ /**
+ * Get all running tasks.
+ *
+ * @return running tasks
+ */
+ public Map<String, Set<TaskContext>> getAllRunningTasks() {
+ return runningService.getAllRunningTasks();
+ }
+
+ /**
+ * Get all failover tasks.
+ *
+ * @return failover tasks
+ */
+ public Map<String, Collection<FailoverTaskInfo>> getAllFailoverTasks() {
+ return failoverService.getAllFailoverTasks();
+ }
+
+ /**
+ * Determine whether the job is disable or not.
+ *
+ * @param jobName job name
+ * @return true is disabled, otherwise not
+ */
+ public boolean isJobDisabled(final String jobName) {
+ Optional<CloudJobConfigurationPOJO> jobConfiguration = jobConfigService.load(jobName);
+ return !jobConfiguration.isPresent() || disableAppService.isDisabled(jobConfiguration.get().getAppName()) || disableJobService.isDisabled(jobName);
+ }
+
+ /**
+ * Enable job.
+ *
+ * @param jobName job name
+ */
+ public void enableJob(final String jobName) {
+ disableJobService.remove(jobName);
+ }
+
+ /**
+ * Disable job.
+ *
+ * @param jobName job name
+ */
+ public void disableJob(final String jobName) {
+ disableJobService.add(jobName);
+ }
+
+
+ /**
+ * Stop facade service.
+ */
+ public void stop() {
+ log.info("Elastic Job: Stop facade service");
+ // TODO stop scheduler
+ runningService.clear();
+ }
+}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/RegistryCenterFactory.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/RegistryCenterFactory.java
index 22755be..c45cc8b 100644
--- a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/RegistryCenterFactory.java
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/RegistryCenterFactory.java
@@ -24,6 +24,8 @@ import com.google.common.hash.Hasher;
import com.google.common.hash.Hashing;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
+import org.apache.shardingsphere.elasticjob.cloud.ui.domain.RegistryCenterConfiguration;
+import org.apache.shardingsphere.elasticjob.cloud.ui.util.SessionRegistryCenterConfiguration;
import org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;
import org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperConfiguration;
import org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter;
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/app/CloudAppConfiguration.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/app/CloudAppConfiguration.java
new file mode 100644
index 0000000..0540821
--- /dev/null
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/app/CloudAppConfiguration.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.cloud.ui.service.app;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.ToString;
+
+/**
+ * Cloud app configuration.
+ */
+@AllArgsConstructor
+@RequiredArgsConstructor
+@Getter
+@ToString
+public final class CloudAppConfiguration {
+
+ private final String appName;
+
+ private final String appURL;
+
+ private final String bootstrapScript;
+
+ private double cpuCount = 1d;
+
+ private double memoryMB = 128d;
+
+ private boolean appCacheEnable = true;
+
+ private int eventTraceSamplingCount;
+}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/app/CloudAppConfigurationNode.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/app/CloudAppConfigurationNode.java
new file mode 100644
index 0000000..2a48ce0
--- /dev/null
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/app/CloudAppConfigurationNode.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.cloud.ui.service.app;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+/**
+ * Cloud app configuration node.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class CloudAppConfigurationNode {
+
+ public static final String ROOT = "/config/app";
+
+ private static final String APP_CONFIG = ROOT + "/%s";
+
+ static String getRootNodePath(final String appName) {
+ return String.format(APP_CONFIG, appName);
+ }
+}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/app/CloudAppConfigurationService.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/app/CloudAppConfigurationService.java
new file mode 100644
index 0000000..afe1dba
--- /dev/null
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/app/CloudAppConfigurationService.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.cloud.ui.service.app;
+
+import com.google.common.base.Strings;
+import lombok.RequiredArgsConstructor;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.app.pojo.CloudAppConfigurationPOJO;
+import org.apache.shardingsphere.elasticjob.infra.yaml.YamlEngine;
+import org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * Cloud app configuration service.
+ */
+@Service("appConfigService")
+public final class CloudAppConfigurationService {
+
+ @Autowired
+ private CoordinatorRegistryCenter regCenter;
+
+ /**
+ * Add cloud app configuration.
+ *
+ * @param appConfig cloud app configuration
+ */
+ public void add(final CloudAppConfigurationPOJO appConfig) {
+ regCenter.persist(CloudAppConfigurationNode.getRootNodePath(appConfig.getAppName()), YamlEngine.marshal(appConfig));
+ }
+
+ /**
+ * Update cloud app configuration.
+ *
+ * @param appConfig cloud app configuration
+ */
+ public void update(final CloudAppConfigurationPOJO appConfig) {
+ regCenter.update(CloudAppConfigurationNode.getRootNodePath(appConfig.getAppName()), YamlEngine.marshal(appConfig));
+ }
+
+ /**
+ * Load app configuration by app name.
+ *
+ * @param appName application name
+ * @return cloud app configuration
+ */
+ public Optional<CloudAppConfigurationPOJO> load(final String appName) {
+ String configContent = regCenter.get(CloudAppConfigurationNode.getRootNodePath(appName));
+ return Strings.isNullOrEmpty(configContent) ? Optional.empty() : Optional.of(YamlEngine.unmarshal(configContent, CloudAppConfigurationPOJO.class));
+ }
+
+ /**
+ * Load all registered cloud app configurations.
+ *
+ * @return collection of the registered cloud app configuration
+ */
+ public Collection<CloudAppConfigurationPOJO> loadAll() {
+ if (!regCenter.isExisted(CloudAppConfigurationNode.ROOT)) {
+ return Collections.emptyList();
+ }
+ List<String> appNames = regCenter.getChildrenKeys(CloudAppConfigurationNode.ROOT);
+ Collection<CloudAppConfigurationPOJO> result = new ArrayList<>(appNames.size());
+ for (String each : appNames) {
+ Optional<CloudAppConfigurationPOJO> config = load(each);
+ config.ifPresent(result::add);
+ }
+ return result;
+ }
+
+ /**
+ * Remove cloud app configuration by app name.
+ *
+ * @param appName to be removed application name
+ */
+ public void remove(final String appName) {
+ regCenter.remove(CloudAppConfigurationNode.getRootNodePath(appName));
+ }
+}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/app/pojo/CloudAppConfigurationPOJO.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/app/pojo/CloudAppConfigurationPOJO.java
new file mode 100644
index 0000000..aa007f6
--- /dev/null
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/app/pojo/CloudAppConfigurationPOJO.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.cloud.ui.service.app.pojo;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.app.CloudAppConfiguration;
+
+/**
+ * Cloud app configuration POJO.
+ */
+@Getter
+@Setter
+public final class CloudAppConfigurationPOJO {
+
+ private String appName;
+
+ private String appURL;
+
+ private String bootstrapScript;
+
+ private double cpuCount = 1d;
+
+ private double memoryMB = 128d;
+
+ private boolean appCacheEnable = true;
+
+ private int eventTraceSamplingCount;
+
+ /**
+ * Convert to cloud app configuration.
+ *
+ * @return cloud app configuration
+ */
+ public CloudAppConfiguration toCloudAppConfiguration() {
+ return new CloudAppConfiguration(appName, appURL, bootstrapScript, cpuCount, memoryMB, appCacheEnable, eventTraceSamplingCount);
+ }
+
+ /**
+ * Convert from cloud app configuration.
+ *
+ * @param cloudAppConfig cloud job configuration
+ * @return cloud app configuration POJO
+ */
+ public static CloudAppConfigurationPOJO fromCloudAppConfiguration(final CloudAppConfiguration cloudAppConfig) {
+ CloudAppConfigurationPOJO result = new CloudAppConfigurationPOJO();
+ result.setAppName(cloudAppConfig.getAppName());
+ result.setAppURL(cloudAppConfig.getAppURL());
+ result.setBootstrapScript(cloudAppConfig.getBootstrapScript());
+ result.setCpuCount(cloudAppConfig.getCpuCount());
+ result.setMemoryMB(cloudAppConfig.getMemoryMB());
+ result.setAppCacheEnable(cloudAppConfig.isAppCacheEnable());
+ result.setEventTraceSamplingCount(cloudAppConfig.getEventTraceSamplingCount());
+ return result;
+ }
+}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/job/CloudJobConfigurationNode.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/job/CloudJobConfigurationNode.java
new file mode 100644
index 0000000..01f2944
--- /dev/null
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/job/CloudJobConfigurationNode.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.cloud.ui.service.job;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+/**
+ * Cloud job configuration node.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class CloudJobConfigurationNode {
+
+ public static final String ROOT = "/config/job";
+
+ private static final String JOB_CONFIG = ROOT + "/%s";
+
+ static String getRootNodePath(final String jobName) {
+ return String.format(JOB_CONFIG, jobName);
+ }
+}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/job/CloudJobConfigurationService.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/job/CloudJobConfigurationService.java
new file mode 100644
index 0000000..11ecc33
--- /dev/null
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/job/CloudJobConfigurationService.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.cloud.ui.service.job;
+
+import com.google.common.base.Strings;
+import org.apache.shardingsphere.elasticjob.cloud.config.pojo.CloudJobConfigurationPOJO;
+import org.apache.shardingsphere.elasticjob.infra.yaml.YamlEngine;
+import org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * Cloud job configuration service.
+ */
+@Service
+public final class CloudJobConfigurationService {
+
+ @Autowired
+ private CoordinatorRegistryCenter regCenter;
+
+ /**
+ * Add cloud job configuration.
+ *
+ * @param cloudJobConfig cloud job configuration
+ */
+ public void add(final CloudJobConfigurationPOJO cloudJobConfig) {
+ regCenter.persist(
+ CloudJobConfigurationNode.getRootNodePath(cloudJobConfig.getJobName()), YamlEngine.marshal(cloudJobConfig));
+ }
+
+ /**
+ * Update cloud job configuration.
+ *
+ * @param cloudJobConfig cloud job configuration
+ */
+ public void update(final CloudJobConfigurationPOJO cloudJobConfig) {
+ regCenter.update(
+ CloudJobConfigurationNode.getRootNodePath(cloudJobConfig.getJobName()), YamlEngine.marshal(cloudJobConfig));
+ }
+
+ /**
+ * Load all registered cloud job configurations.
+ *
+ * @return collection of the registered cloud job configuration
+ */
+ public Collection<CloudJobConfigurationPOJO> loadAll() {
+ if (!regCenter.isExisted(CloudJobConfigurationNode.ROOT)) {
+ return Collections.emptyList();
+ }
+ List<String> jobNames = regCenter.getChildrenKeys(CloudJobConfigurationNode.ROOT);
+ Collection<CloudJobConfigurationPOJO> result = new ArrayList<>(jobNames.size());
+ for (String each : jobNames) {
+ load(each).ifPresent(result::add);
+ }
+ return result;
+ }
+
+ /**
+ * Load cloud job configuration by job name.
+ *
+ * @param jobName job name
+ * @return cloud job configuration
+ */
+ public Optional<CloudJobConfigurationPOJO> load(final String jobName) {
+ String configContent = regCenter.get(CloudJobConfigurationNode.getRootNodePath(jobName));
+ return Strings.isNullOrEmpty(configContent) ? Optional.empty() : Optional.of(YamlEngine.unmarshal(configContent, CloudJobConfigurationPOJO.class));
+ }
+
+ /**
+ * Remove cloud job configuration.
+ *
+ * @param jobName job name
+ */
+ public void remove(final String jobName) {
+ regCenter.remove(CloudJobConfigurationNode.getRootNodePath(jobName));
+ }
+}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/producer/ProducerManager.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/producer/ProducerManager.java
new file mode 100644
index 0000000..21ae5c3
--- /dev/null
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/producer/ProducerManager.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.cloud.ui.service.producer;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shardingsphere.elasticjob.cloud.config.pojo.CloudJobConfigurationPOJO;
+import org.apache.shardingsphere.elasticjob.cloud.ui.exception.AppConfigurationException;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.app.CloudAppConfigurationService;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.app.pojo.CloudAppConfigurationPOJO;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.job.CloudJobConfigurationService;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.state.disable.job.DisableJobService;
+import org.apache.shardingsphere.elasticjob.infra.exception.JobConfigurationException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Optional;
+
+/**
+ * Producer manager.
+ */
+@Slf4j
+@Service
+public final class ProducerManager {
+
+ @Autowired
+ private CloudAppConfigurationService appConfigService;
+
+ @Autowired
+ private CloudJobConfigurationService configService;
+
+ @Autowired
+ private DisableJobService disableJobService;
+
+ /**
+ * Register the job.
+ *
+ * @param cloudJobConfig cloud job configuration
+ */
+ public void register(final CloudJobConfigurationPOJO cloudJobConfig) {
+ if (disableJobService.isDisabled(cloudJobConfig.getJobName())) {
+ throw new JobConfigurationException("Job '%s' has been disable.", cloudJobConfig.getJobName());
+ }
+ Optional<CloudAppConfigurationPOJO> appConfigFromZk = appConfigService.load(cloudJobConfig.getAppName());
+ if (!appConfigFromZk.isPresent()) {
+ throw new AppConfigurationException("Register app '%s' firstly.", cloudJobConfig.getAppName());
+ }
+ Optional<CloudJobConfigurationPOJO> jobConfigFromZk = configService.load(cloudJobConfig.getJobName());
+ if (jobConfigFromZk.isPresent()) {
+ throw new JobConfigurationException("Job '%s' already existed.", cloudJobConfig.getJobName());
+ }
+ configService.add(cloudJobConfig);
+ }
+
+ /**
+ * Update the job.
+ *
+ * @param cloudJobConfig cloud job configuration
+ */
+ public void update(final CloudJobConfigurationPOJO cloudJobConfig) {
+ Optional<CloudJobConfigurationPOJO> jobConfigFromZk = configService.load(cloudJobConfig.getJobName());
+ if (!jobConfigFromZk.isPresent()) {
+ throw new JobConfigurationException("Cannot found job '%s', please register first.", cloudJobConfig.getJobName());
+ }
+ configService.update(cloudJobConfig);
+ }
+
+ /**
+ * Deregister the job.
+ *
+ * @param jobName job name
+ */
+ public void deregister(final String jobName) {
+ Optional<CloudJobConfigurationPOJO> jobConfig = configService.load(jobName);
+ if (jobConfig.isPresent()) {
+ disableJobService.remove(jobName);
+ configService.remove(jobName);
+ }
+ }
+}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/StateNode.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/StateNode.java
new file mode 100644
index 0000000..218c1e1
--- /dev/null
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/StateNode.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.cloud.ui.service.state;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+/**
+ * State node.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class StateNode {
+
+ /**
+ * Root state node.
+ */
+ public static final String ROOT = "/state";
+}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/disable/app/DisableAppNode.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/disable/app/DisableAppNode.java
new file mode 100644
index 0000000..4c7b13e
--- /dev/null
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/disable/app/DisableAppNode.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.cloud.ui.service.state.disable.app;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.state.StateNode;
+
+/**
+ * Disable app node.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+final class DisableAppNode {
+
+ static final String ROOT = StateNode.ROOT + "/disable/app";
+
+ private static final String DISABLE_APP = ROOT + "/%s";
+
+ static String getDisableAppNodePath(final String appName) {
+ return String.format(DISABLE_APP, appName);
+ }
+}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/disable/app/DisableAppService.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/disable/app/DisableAppService.java
new file mode 100644
index 0000000..3e7d884
--- /dev/null
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/disable/app/DisableAppService.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.cloud.ui.service.state.disable.app;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shardingsphere.elasticjob.cloud.ui.config.JobStateConfiguration;
+import org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * Disable app service.
+ */
+@Slf4j
+@Service
+public class DisableAppService {
+
+ @Autowired
+ private CoordinatorRegistryCenter regCenter;
+
+ @Autowired
+ private JobStateConfiguration jobStateConfiguration;
+
+ /**
+ * Add application name to disable queue.
+ *
+ * @param appName application name
+ */
+ public void add(final String appName) {
+ if (regCenter.getNumChildren(DisableAppNode.ROOT) > jobStateConfiguration.getQueueSize()) {
+ log.warn("Cannot add disable app, caused by read state queue size is larger than {}.", jobStateConfiguration.getQueueSize());
+ return;
+ }
+ String disableAppNodePath = DisableAppNode.getDisableAppNodePath(appName);
+ if (!regCenter.isExisted(disableAppNodePath)) {
+ regCenter.persist(disableAppNodePath, appName);
+ }
+ }
+
+ /**
+ * Remove application name from disable queue.
+ *
+ * @param appName application name
+ */
+ public void remove(final String appName) {
+ regCenter.remove(DisableAppNode.getDisableAppNodePath(appName));
+ }
+
+ /**
+ * Check whether the application name is disabled or not.
+ *
+ * @param appName application name
+ * @return true is in the disable queue, otherwise not
+ */
+ public boolean isDisabled(final String appName) {
+ return regCenter.isExisted(DisableAppNode.getDisableAppNodePath(appName));
+ }
+}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/disable/job/DisableJobNode.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/disable/job/DisableJobNode.java
new file mode 100644
index 0000000..fdd7eab
--- /dev/null
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/disable/job/DisableJobNode.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.cloud.ui.service.state.disable.job;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.state.StateNode;
+
+/**
+ * Disable job node.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+final class DisableJobNode {
+
+ static final String ROOT = StateNode.ROOT + "/disable/job";
+
+ private static final String DISABLE_JOB = ROOT + "/%s";
+
+ static String getDisableJobNodePath(final String jobName) {
+ return String.format(DISABLE_JOB, jobName);
+ }
+}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/disable/job/DisableJobService.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/disable/job/DisableJobService.java
new file mode 100644
index 0000000..9e1cee8
--- /dev/null
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/disable/job/DisableJobService.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.cloud.ui.service.state.disable.job;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shardingsphere.elasticjob.cloud.ui.config.JobStateConfiguration;
+import org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * Disable job service.
+ */
+@Slf4j
+@Service
+public class DisableJobService {
+
+ @Autowired
+ private CoordinatorRegistryCenter regCenter;
+
+ @Autowired
+ private JobStateConfiguration jobStateConfiguration;
+
+ /**
+ * Add job to the disable queue.
+ *
+ * @param jobName job name
+ */
+ public void add(final String jobName) {
+ if (regCenter.getNumChildren(DisableJobNode.ROOT) > jobStateConfiguration.getQueueSize()) {
+ log.warn("Cannot add disable job, caused by read state queue size is larger than {}.", jobStateConfiguration.getQueueSize());
+ return;
+ }
+ String disableJobNodePath = DisableJobNode.getDisableJobNodePath(jobName);
+ if (!regCenter.isExisted(disableJobNodePath)) {
+ regCenter.persist(disableJobNodePath, jobName);
+ }
+ }
+
+ /**
+ * Remove the job from the disable queue.
+ *
+ * @param jobName job name
+ */
+ public void remove(final String jobName) {
+ regCenter.remove(DisableJobNode.getDisableJobNodePath(jobName));
+ }
+
+ /**
+ * Determine whether the job is in the disable queue or not.
+ *
+ * @param jobName job name
+ * @return true is in the disable queue, otherwise not
+ */
+ public boolean isDisabled(final String jobName) {
+ return regCenter.isExisted(DisableJobNode.getDisableJobNodePath(jobName));
+ }
+}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/failover/FailoverNode.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/failover/FailoverNode.java
new file mode 100644
index 0000000..002f07a
--- /dev/null
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/failover/FailoverNode.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.cloud.ui.service.state.failover;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.state.StateNode;
+import org.apache.shardingsphere.elasticjob.infra.context.TaskContext.MetaInfo;
+
+/**
+ * Failover node.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+final class FailoverNode {
+
+ static final String ROOT = StateNode.ROOT + "/failover";
+
+ private static final String FAILOVER_JOB = ROOT + "/%s";
+
+ private static final String FAILOVER_TASK = FAILOVER_JOB + "/%s";
+
+ static String getFailoverJobNodePath(final String jobName) {
+ return String.format(FAILOVER_JOB, jobName);
+ }
+
+ static String getFailoverTaskNodePath(final String taskMetaInfo) {
+ return String.format(FAILOVER_TASK, MetaInfo.from(taskMetaInfo).getJobName(), taskMetaInfo);
+ }
+}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/failover/FailoverService.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/failover/FailoverService.java
new file mode 100644
index 0000000..b98d8ed
--- /dev/null
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/failover/FailoverService.java
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.cloud.ui.service.state.failover;
+
+import com.google.common.base.Strings;
+import com.google.common.hash.HashCode;
+import com.google.common.hash.Hashing;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shardingsphere.elasticjob.cloud.ui.config.JobStateConfiguration;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.state.running.RunningService;
+import org.apache.shardingsphere.elasticjob.infra.context.TaskContext;
+import org.apache.shardingsphere.elasticjob.infra.context.TaskContext.MetaInfo;
+import org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * Failover service.
+ */
+@Slf4j
+@Service
+public final class FailoverService {
+
+ @Autowired
+ private CoordinatorRegistryCenter regCenter;
+
+ @Autowired
+ private RunningService runningService;
+
+ @Autowired
+ private JobStateConfiguration jobStateConfiguration;
+
+ /**
+ * Add task to failover queue.
+ *
+ * @param taskContext task running context
+ */
+ public void add(final TaskContext taskContext) {
+ if (regCenter.getNumChildren(FailoverNode.ROOT) > jobStateConfiguration.getQueueSize()) {
+ log.warn("Cannot add job, caused by read state queue size is larger than {}.", jobStateConfiguration.getQueueSize());
+ return;
+ }
+ String failoverTaskNodePath = FailoverNode.getFailoverTaskNodePath(taskContext.getMetaInfo().toString());
+ if (!regCenter.isExisted(failoverTaskNodePath) && !runningService.isTaskRunning(taskContext.getMetaInfo())) {
+ // TODO Whether Daemon-type jobs increase storage and fail immediately?
+ regCenter.persist(failoverTaskNodePath, taskContext.getId());
+ }
+ }
+
+ private List<Integer> getAssignedShardingItems(final String jobName, final List<String> taskIdList, final Set<HashCode> assignedTasks) {
+ List<Integer> result = new ArrayList<>(taskIdList.size());
+ for (String each : taskIdList) {
+ MetaInfo metaInfo = MetaInfo.from(each);
+ if (assignedTasks.add(Hashing.sha256().newHasher().putString(jobName, StandardCharsets.UTF_8).putInt(metaInfo.getShardingItems().get(0)).hash())
+ && !runningService.isTaskRunning(metaInfo)) {
+ result.add(metaInfo.getShardingItems().get(0));
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Remove task from the failover queue.
+ *
+ * @param metaInfoList collection of task meta infos to be removed
+ */
+ public void remove(final Collection<MetaInfo> metaInfoList) {
+ for (MetaInfo each : metaInfoList) {
+ regCenter.remove(FailoverNode.getFailoverTaskNodePath(each.toString()));
+ }
+ }
+
+ /**
+ * Get task id from failover queue.
+ *
+ * @param metaInfo task meta info
+ * @return failover task id
+ */
+ public Optional<String> getTaskId(final MetaInfo metaInfo) {
+ String failoverTaskNodePath = FailoverNode.getFailoverTaskNodePath(metaInfo.toString());
+ return regCenter.isExisted(failoverTaskNodePath) ? Optional.of(regCenter.get(failoverTaskNodePath)) : Optional.empty();
+ }
+
+ /**
+ * Get all failover tasks.
+ *
+ * @return all failover tasks
+ */
+ public Map<String, Collection<FailoverTaskInfo>> getAllFailoverTasks() {
+ if (!regCenter.isExisted(FailoverNode.ROOT)) {
+ return Collections.emptyMap();
+ }
+ List<String> jobNames = regCenter.getChildrenKeys(FailoverNode.ROOT);
+ Map<String, Collection<FailoverTaskInfo>> result = new HashMap<>(jobNames.size(), 1);
+ for (String each : jobNames) {
+ Collection<FailoverTaskInfo> failoverTasks = getFailoverTasks(each);
+ if (!failoverTasks.isEmpty()) {
+ result.put(each, failoverTasks);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Get failover tasks.
+ *
+ * @param jobName job name
+ * @return collection of failover tasks
+ */
+ private Collection<FailoverTaskInfo> getFailoverTasks(final String jobName) {
+ List<String> failOverTasks = regCenter.getChildrenKeys(FailoverNode.getFailoverJobNodePath(jobName));
+ List<FailoverTaskInfo> result = new ArrayList<>(failOverTasks.size());
+ for (String each : failOverTasks) {
+ String originalTaskId = regCenter.get(FailoverNode.getFailoverTaskNodePath(each));
+ if (!Strings.isNullOrEmpty(originalTaskId)) {
+ result.add(new FailoverTaskInfo(MetaInfo.from(each), originalTaskId));
+ }
+ }
+ return result;
+ }
+}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/failover/FailoverTaskInfo.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/failover/FailoverTaskInfo.java
new file mode 100644
index 0000000..77641f3
--- /dev/null
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/failover/FailoverTaskInfo.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.cloud.ui.service.state.failover;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import org.apache.shardingsphere.elasticjob.infra.context.TaskContext.MetaInfo;
+
+/**
+ * Failover task info.
+ */
+@RequiredArgsConstructor
+@Getter
+public final class FailoverTaskInfo {
+
+ private final MetaInfo taskInfo;
+
+ private final String originalTaskId;
+}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/ready/ReadyNode.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/ready/ReadyNode.java
new file mode 100644
index 0000000..ea0aceb
--- /dev/null
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/ready/ReadyNode.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.cloud.ui.service.state.ready;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.state.StateNode;
+
+/**
+ * Ready node.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+final class ReadyNode {
+
+ static final String ROOT = StateNode.ROOT + "/ready";
+
+ private static final String READY_JOB = ROOT + "/%s";
+
+ static String getReadyJobNodePath(final String jobName) {
+ return String.format(READY_JOB, jobName);
+ }
+}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/ready/ReadyService.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/ready/ReadyService.java
new file mode 100644
index 0000000..b5544a6
--- /dev/null
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/ready/ReadyService.java
@@ -0,0 +1,147 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.cloud.ui.service.state.ready;
+
+import com.google.common.base.Strings;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shardingsphere.elasticjob.cloud.config.CloudJobExecutionType;
+import org.apache.shardingsphere.elasticjob.cloud.config.pojo.CloudJobConfigurationPOJO;
+import org.apache.shardingsphere.elasticjob.cloud.ui.config.JobStateConfiguration;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.job.CloudJobConfigurationService;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.state.running.RunningService;
+import org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * Ready service.
+ */
+@Slf4j
+@Service
+public final class ReadyService {
+
+ @Autowired
+ private CoordinatorRegistryCenter regCenter;
+
+ @Autowired
+ private CloudJobConfigurationService configService;
+
+ @Autowired
+ private RunningService runningService;
+
+ @Autowired
+ private JobStateConfiguration jobStateConfiguration;
+
+
+ /**
+ * Add transient job to ready queue.
+ *
+ * @param jobName job name
+ */
+ public void addTransient(final String jobName) {
+ if (regCenter.getNumChildren(ReadyNode.ROOT) > jobStateConfiguration.getQueueSize()) {
+ log.warn("Cannot add transient job, caused by read state queue size is larger than {}.", jobStateConfiguration.getQueueSize());
+ return;
+ }
+ Optional<CloudJobConfigurationPOJO> cloudJobConfig = configService.load(jobName);
+ if (!cloudJobConfig.isPresent() || CloudJobExecutionType.TRANSIENT != cloudJobConfig.get().getJobExecutionType()) {
+ return;
+ }
+ String readyJobNode = ReadyNode.getReadyJobNodePath(jobName);
+ String times = regCenter.getDirectly(readyJobNode);
+ if (cloudJobConfig.get().isMisfire()) {
+ regCenter.persist(readyJobNode, Integer.toString(null == times ? 1 : Integer.parseInt(times) + 1));
+ } else {
+ regCenter.persist(ReadyNode.getReadyJobNodePath(jobName), "1");
+ }
+ }
+
+ /**
+ * Add daemon job to ready queue.
+ *
+ * @param jobName job name
+ */
+ public void addDaemon(final String jobName) {
+ if (regCenter.getNumChildren(ReadyNode.ROOT) > jobStateConfiguration.getQueueSize()) {
+ log.warn("Cannot add daemon job, caused by read state queue size is larger than {}.", jobStateConfiguration.getQueueSize());
+ return;
+ }
+ Optional<CloudJobConfigurationPOJO> cloudJobConfig = configService.load(jobName);
+ if (!cloudJobConfig.isPresent() || CloudJobExecutionType.DAEMON != cloudJobConfig.get().getJobExecutionType() || runningService.isJobRunning(jobName)) {
+ return;
+ }
+ regCenter.persist(ReadyNode.getReadyJobNodePath(jobName), "1");
+ }
+
+ /**
+ * Set misfire disabled.
+ *
+ * @param jobName job name
+ */
+ public void setMisfireDisabled(final String jobName) {
+ Optional<CloudJobConfigurationPOJO> cloudJobConfig = configService.load(jobName);
+ if (cloudJobConfig.isPresent() && null != regCenter.getDirectly(ReadyNode.getReadyJobNodePath(jobName))) {
+ regCenter.persist(ReadyNode.getReadyJobNodePath(jobName), "1");
+ }
+ }
+
+ /**
+ * Remove jobs from ready queue.
+ *
+ * @param jobNames collection of jobs to be removed
+ */
+ public void remove(final Collection<String> jobNames) {
+ for (String each : jobNames) {
+ String readyJobNode = ReadyNode.getReadyJobNodePath(each);
+ String timesStr = regCenter.getDirectly(readyJobNode);
+ int times = null == timesStr ? 0 : Integer.parseInt(timesStr);
+ if (times <= 1) {
+ regCenter.remove(readyJobNode);
+ } else {
+ regCenter.persist(readyJobNode, Integer.toString(times - 1));
+ }
+ }
+ }
+
+ /**
+ * Get all ready tasks.
+ *
+ * @return all ready tasks
+ */
+ public Map<String, Integer> getAllReadyTasks() {
+ if (!regCenter.isExisted(ReadyNode.ROOT)) {
+ return Collections.emptyMap();
+ }
+ List<String> jobNames = regCenter.getChildrenKeys(ReadyNode.ROOT);
+ Map<String, Integer> result = new HashMap<>(jobNames.size(), 1);
+ for (String each : jobNames) {
+ String times = regCenter.get(ReadyNode.getReadyJobNodePath(each));
+ if (!Strings.isNullOrEmpty(times)) {
+ result.put(each, Integer.parseInt(times));
+ }
+ }
+ return result;
+ }
+}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/running/RunningNode.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/running/RunningNode.java
new file mode 100644
index 0000000..9d0d8c8
--- /dev/null
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/running/RunningNode.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.cloud.ui.service.state.running;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.state.StateNode;
+import org.apache.shardingsphere.elasticjob.infra.context.TaskContext.MetaInfo;
+
+/**
+ * Running node.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+final class RunningNode {
+
+ static final String ROOT = StateNode.ROOT + "/running";
+
+ private static final String RUNNING_JOB = ROOT + "/%s";
+
+ private static final String RUNNING_TASK = RUNNING_JOB + "/%s";
+
+ static String getRunningJobNodePath(final String jobName) {
+ return String.format(RUNNING_JOB, jobName);
+ }
+
+ static String getRunningTaskNodePath(final String taskMetaInfo) {
+ return String.format(RUNNING_TASK, MetaInfo.from(taskMetaInfo).getJobName(), taskMetaInfo);
+ }
+}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/running/RunningService.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/running/RunningService.java
new file mode 100644
index 0000000..7de20fc
--- /dev/null
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/state/running/RunningService.java
@@ -0,0 +1,253 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.cloud.ui.service.state.running;
+
+import com.google.common.collect.Sets;
+import lombok.Getter;
+import org.apache.shardingsphere.elasticjob.cloud.config.CloudJobExecutionType;
+import org.apache.shardingsphere.elasticjob.cloud.config.pojo.CloudJobConfigurationPOJO;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.job.CloudJobConfigurationService;
+import org.apache.shardingsphere.elasticjob.infra.context.TaskContext;
+import org.apache.shardingsphere.elasticjob.infra.context.TaskContext.MetaInfo;
+import org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.stream.Collectors;
+
+/**
+ * Running service.
+ */
+@Service
+public final class RunningService {
+
+ private static final int TASK_INITIAL_SIZE = 1024;
+
+ // TODO Using JMX to export
+ @Getter
+ private static final ConcurrentHashMap<String, Set<TaskContext>> RUNNING_TASKS = new ConcurrentHashMap<>(TASK_INITIAL_SIZE);
+
+ private static final ConcurrentHashMap<String, String> TASK_HOSTNAME_MAPPER = new ConcurrentHashMap<>(TASK_INITIAL_SIZE);
+
+ @Autowired
+ private CoordinatorRegistryCenter regCenter;
+
+ @Autowired
+ private CloudJobConfigurationService configurationService;
+
+ /**
+ * Start running queue service.
+ */
+ public void start() {
+ clear();
+ List<String> jobKeys = regCenter.getChildrenKeys(RunningNode.ROOT);
+ for (String each : jobKeys) {
+ if (!configurationService.load(each).isPresent()) {
+ remove(each);
+ continue;
+ }
+ RUNNING_TASKS.put(each, Sets.newCopyOnWriteArraySet(regCenter.getChildrenKeys(RunningNode.getRunningJobNodePath(each)).stream().map(
+ input -> TaskContext.from(regCenter.get(RunningNode.getRunningTaskNodePath(MetaInfo.from(input).toString())))).collect(Collectors.toList())));
+ }
+ }
+
+ /**
+ * Add task to running queue.
+ *
+ * @param taskContext task running context
+ */
+ public void add(final TaskContext taskContext) {
+ if (!configurationService.load(taskContext.getMetaInfo().getJobName()).isPresent()) {
+ return;
+ }
+ getRunningTasks(taskContext.getMetaInfo().getJobName()).add(taskContext);
+ if (!isDaemon(taskContext.getMetaInfo().getJobName())) {
+ return;
+ }
+ String runningTaskNodePath = RunningNode.getRunningTaskNodePath(taskContext.getMetaInfo().toString());
+ if (!regCenter.isExisted(runningTaskNodePath)) {
+ regCenter.persist(runningTaskNodePath, taskContext.getId());
+ }
+ }
+
+ private boolean isDaemon(final String jobName) {
+ Optional<CloudJobConfigurationPOJO> cloudJobConfig = configurationService.load(jobName);
+ return cloudJobConfig.isPresent() && CloudJobExecutionType.DAEMON == cloudJobConfig.get().getJobExecutionType();
+ }
+
+ /**
+ * Update task to idle state.
+ *
+ * @param taskContext task running context
+ * @param isIdle is idle
+ */
+ public void updateIdle(final TaskContext taskContext, final boolean isIdle) {
+ synchronized (RUNNING_TASKS) {
+ Optional<TaskContext> taskContextOptional = findTask(taskContext);
+ if (taskContextOptional.isPresent()) {
+ taskContextOptional.get().setIdle(isIdle);
+ } else {
+ add(taskContext);
+ }
+ }
+ }
+
+ private Optional<TaskContext> findTask(final TaskContext taskContext) {
+ return getRunningTasks(taskContext.getMetaInfo().getJobName()).stream().filter(each -> each.equals(taskContext)).findFirst();
+ }
+
+ /**
+ * Remove job from running queue.
+ *
+ * @param jobName job name
+ */
+ public void remove(final String jobName) {
+ RUNNING_TASKS.remove(jobName);
+ if (!isDaemonOrAbsent(jobName)) {
+ return;
+ }
+ regCenter.remove(RunningNode.getRunningJobNodePath(jobName));
+ }
+
+ /**
+ * Remove task from running queue.
+ *
+ * @param taskContext task running context
+ */
+ public void remove(final TaskContext taskContext) {
+ getRunningTasks(taskContext.getMetaInfo().getJobName()).remove(taskContext);
+ if (!isDaemonOrAbsent(taskContext.getMetaInfo().getJobName())) {
+ return;
+ }
+ regCenter.remove(RunningNode.getRunningTaskNodePath(taskContext.getMetaInfo().toString()));
+ String jobRootNode = RunningNode.getRunningJobNodePath(taskContext.getMetaInfo().getJobName());
+ if (regCenter.isExisted(jobRootNode) && regCenter.getChildrenKeys(jobRootNode).isEmpty()) {
+ regCenter.remove(jobRootNode);
+ }
+ }
+
+ private boolean isDaemonOrAbsent(final String jobName) {
+ Optional<CloudJobConfigurationPOJO> cloudJobConfigurationOptional = configurationService.load(jobName);
+ return !cloudJobConfigurationOptional.isPresent() || CloudJobExecutionType.DAEMON == cloudJobConfigurationOptional.get().getJobExecutionType();
+ }
+
+ /**
+ * Determine whether the job is running or not.
+ *
+ * @param jobName job name
+ * @return true is running, otherwise not
+ */
+ public boolean isJobRunning(final String jobName) {
+ return !getRunningTasks(jobName).isEmpty();
+ }
+
+ /**
+ * Determine whether the task is running or not.
+ *
+ * @param metaInfo task meta info
+ * @return true is running, otherwise not
+ */
+ public boolean isTaskRunning(final MetaInfo metaInfo) {
+ for (TaskContext each : getRunningTasks(metaInfo.getJobName())) {
+ if (each.getMetaInfo().equals(metaInfo)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Get running tasks by job name.
+ *
+ * @param jobName job name
+ * @return collection of the running tasks
+ */
+ public Collection<TaskContext> getRunningTasks(final String jobName) {
+ Set<TaskContext> taskContexts = new CopyOnWriteArraySet<>();
+ Collection<TaskContext> result = RUNNING_TASKS.putIfAbsent(jobName, taskContexts);
+ return null == result ? taskContexts : result;
+ }
+
+ /**
+ * Get all running tasks.
+ *
+ * @return collection of all the running tasks
+ */
+ public Map<String, Set<TaskContext>> getAllRunningTasks() {
+ Map<String, Set<TaskContext>> result = new HashMap<>(RUNNING_TASKS.size(), 1);
+ result.putAll(RUNNING_TASKS);
+ return result;
+ }
+
+ /**
+ * Get all running daemon tasks.
+ *
+ * @return collection of all the running daemon tasks
+ */
+ public Set<TaskContext> getAllRunningDaemonTasks() {
+ List<String> jobKeys = regCenter.getChildrenKeys(RunningNode.ROOT);
+ for (String each : jobKeys) {
+ if (!RUNNING_TASKS.containsKey(each)) {
+ remove(each);
+ }
+ }
+ Set<TaskContext> result = Sets.newHashSet();
+ for (Map.Entry<String, Set<TaskContext>> each : RUNNING_TASKS.entrySet()) {
+ if (isDaemonOrAbsent(each.getKey())) {
+ result.addAll(each.getValue());
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Add mapping of task primary key and hostname.
+ *
+ * @param taskId task primary key
+ * @param hostname host name
+ */
+ public void addMapping(final String taskId, final String hostname) {
+ TASK_HOSTNAME_MAPPER.putIfAbsent(taskId, hostname);
+ }
+
+ /**
+ * Retrieve the hostname and then remove this task from the mapping.
+ *
+ * @param taskId task primary key
+ * @return the host name of the removed task
+ */
+ public String popMapping(final String taskId) {
+ return TASK_HOSTNAME_MAPPER.remove(taskId);
+ }
+
+ /**
+ * Clear the running status.
+ */
+ public void clear() {
+ RUNNING_TASKS.clear();
+ TASK_HOSTNAME_MAPPER.clear();
+ }
+}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/statistics/StatisticManager.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/statistics/StatisticManager.java
new file mode 100644
index 0000000..8b148eb
--- /dev/null
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/statistics/StatisticManager.java
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.cloud.ui.service.statistics;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shardingsphere.elasticjob.cloud.config.CloudJobExecutionType;
+import org.apache.shardingsphere.elasticjob.cloud.config.pojo.CloudJobConfigurationPOJO;
+import org.apache.shardingsphere.elasticjob.cloud.statistics.StatisticInterval;
+import org.apache.shardingsphere.elasticjob.cloud.statistics.type.job.JobExecutionTypeStatistics;
+import org.apache.shardingsphere.elasticjob.cloud.statistics.type.job.JobRegisterStatistics;
+import org.apache.shardingsphere.elasticjob.cloud.statistics.type.job.JobRunningStatistics;
+import org.apache.shardingsphere.elasticjob.cloud.statistics.type.task.TaskResultStatistics;
+import org.apache.shardingsphere.elasticjob.cloud.statistics.type.task.TaskRunningStatistics;
+import org.apache.shardingsphere.elasticjob.cloud.ui.repository.StatisticRdbRepository;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.job.CloudJobConfigurationService;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.statistics.util.StatisticTimeUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * Statistic manager.
+ */
+@Slf4j
+@Service
+public final class StatisticManager {
+
+ @Autowired
+ private CloudJobConfigurationService configurationService;
+
+ @Autowired
+ private StatisticRdbRepository rdbRepository;
+
+ private boolean isRdbConfigured() {
+ return rdbRepository.isEnable();
+ }
+
+ /**
+ * Get statistic of the recent week.
+ * @return task result statistic
+ */
+ public TaskResultStatistics getTaskResultStatisticsWeekly() {
+ if (!isRdbConfigured()) {
+ return new TaskResultStatistics(0, 0, StatisticInterval.DAY, new Date());
+ }
+ return rdbRepository.getSummedTaskResultStatistics(StatisticTimeUtils.getStatisticTime(StatisticInterval.DAY, -7), StatisticInterval.DAY);
+ }
+
+ /**
+ * Get statistic since online.
+ *
+ * @return task result statistic
+ */
+ public TaskResultStatistics getTaskResultStatisticsSinceOnline() {
+ if (!isRdbConfigured()) {
+ return new TaskResultStatistics(0, 0, StatisticInterval.DAY, new Date());
+ }
+ return rdbRepository.getSummedTaskResultStatistics(getOnlineDate(), StatisticInterval.DAY);
+ }
+
+ /**
+ * Get the latest statistic of the specified interval.
+ * @param statisticInterval statistic interval
+ * @return task result statistic
+ */
+ public TaskResultStatistics findLatestTaskResultStatistics(final StatisticInterval statisticInterval) {
+ if (isRdbConfigured()) {
+ Optional<TaskResultStatistics> result = rdbRepository.findLatestTaskResultStatistics(statisticInterval);
+ if (result.isPresent()) {
+ return result.get();
+ }
+ }
+ return new TaskResultStatistics(0, 0, statisticInterval, new Date());
+ }
+
+ /**
+ * Get statistic of the recent day.
+ *
+ * @return task result statistic
+ */
+ public List<TaskResultStatistics> findTaskResultStatisticsDaily() {
+ if (!isRdbConfigured()) {
+ return Collections.emptyList();
+ }
+ return rdbRepository.findTaskResultStatistics(StatisticTimeUtils.getStatisticTime(StatisticInterval.HOUR, -24), StatisticInterval.MINUTE);
+ }
+
+ /**
+ * Get job execution type statistics.
+ *
+ * @return Job execution type statistics data object
+ */
+ public JobExecutionTypeStatistics getJobExecutionTypeStatistics() {
+ int transientJobCnt = 0;
+ int daemonJobCnt = 0;
+ for (CloudJobConfigurationPOJO each : configurationService.loadAll()) {
+ if (CloudJobExecutionType.TRANSIENT.equals(each.getJobExecutionType())) {
+ transientJobCnt++;
+ } else if (CloudJobExecutionType.DAEMON.equals(each.getJobExecutionType())) {
+ daemonJobCnt++;
+ }
+ }
+ return new JobExecutionTypeStatistics(transientJobCnt, daemonJobCnt);
+ }
+
+ /**
+ * Get the collection of task statistics in the most recent week.
+ *
+ * @return Collection of running task statistics data objects
+ */
+ public List<TaskRunningStatistics> findTaskRunningStatisticsWeekly() {
+ if (!isRdbConfigured()) {
+ return Collections.emptyList();
+ }
+ return rdbRepository.findTaskRunningStatistics(StatisticTimeUtils.getStatisticTime(StatisticInterval.DAY, -7));
+ }
+
+ /**
+ * Get the collection of job statistics in the most recent week.
+ *
+ * @return collection of running task statistics data objects
+ */
+ public List<JobRunningStatistics> findJobRunningStatisticsWeekly() {
+ if (!isRdbConfigured()) {
+ return Collections.emptyList();
+ }
+ return rdbRepository.findJobRunningStatistics(StatisticTimeUtils.getStatisticTime(StatisticInterval.DAY, -7));
+ }
+
+ /**
+ * Get running task statistics data collection since online.
+ *
+ * @return collection of running task statistics data objects
+ */
+ public List<JobRegisterStatistics> findJobRegisterStatisticsSinceOnline() {
+ if (!isRdbConfigured()) {
+ return Collections.emptyList();
+ }
+ return rdbRepository.findJobRegisterStatistics(getOnlineDate());
+ }
+
+ private Date getOnlineDate() {
+ SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
+ try {
+ return formatter.parse("2016-12-16");
+ } catch (final ParseException ex) {
+ return null;
+ }
+ }
+}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/statistics/TaskResultMetaData.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/statistics/TaskResultMetaData.java
new file mode 100644
index 0000000..e7dde23
--- /dev/null
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/statistics/TaskResultMetaData.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.cloud.ui.service.statistics;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Task result meta data.
+ */
+public final class TaskResultMetaData {
+
+ private final AtomicInteger successCount;
+
+ private final AtomicInteger failedCount;
+
+ public TaskResultMetaData() {
+ successCount = new AtomicInteger(0);
+ failedCount = new AtomicInteger(0);
+ }
+
+ /**
+ * Increase and get success count.
+ *
+ * @return success count
+ */
+ public int incrementAndGetSuccessCount() {
+ return successCount.incrementAndGet();
+ }
+
+ /**
+ * Increase and get failed count.
+ *
+ * @return failed count
+ */
+ public int incrementAndGetFailedCount() {
+ return failedCount.incrementAndGet();
+ }
+
+ /**
+ * Get success count.
+ *
+ * @return success count
+ */
+ public int getSuccessCount() {
+ return successCount.get();
+ }
+
+ /**
+ * Get failed count.
+ *
+ * @return failed count
+ */
+ public int getFailedCount() {
+ return failedCount.get();
+ }
+
+ /**
+ * Reset success and failed count.
+ */
+ public void reset() {
+ successCount.set(0);
+ failedCount.set(0);
+ }
+}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/statistics/util/StatisticTimeUtils.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/statistics/util/StatisticTimeUtils.java
new file mode 100644
index 0000000..4be71ad
--- /dev/null
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/service/statistics/util/StatisticTimeUtils.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.cloud.ui.service.statistics.util;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.shardingsphere.elasticjob.cloud.statistics.StatisticInterval;
+
+import java.util.Calendar;
+import java.util.Date;
+
+/**
+ * Statistic time utility.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class StatisticTimeUtils {
+
+ /**
+ * Get the statistical time with the interval unit.
+ *
+ * @param interval interval
+ * @return Date
+ */
+ public static Date getCurrentStatisticTime(final StatisticInterval interval) {
+ return getStatisticTime(interval, 0);
+ }
+
+ /**
+ * Get the statistical time with the interval unit.
+ *
+ * @param interval interval
+ * @param offset offset
+ * @return Date
+ */
+ public static Date getStatisticTime(final StatisticInterval interval, final int offset) {
+ Calendar calendar = Calendar.getInstance();
+ calendar.set(Calendar.MILLISECOND, 0);
+ calendar.set(Calendar.SECOND, 0);
+ switch (interval) {
+ case DAY:
+ calendar.set(Calendar.MINUTE, 0);
+ calendar.set(Calendar.HOUR_OF_DAY, 0);
+ calendar.add(Calendar.DATE, offset);
+ break;
+ case HOUR:
+ calendar.set(Calendar.MINUTE, 0);
+ calendar.add(Calendar.HOUR_OF_DAY, offset);
+ break;
+ case MINUTE:
+ default:
+ calendar.add(Calendar.MINUTE, offset);
+ break;
+ }
+ return calendar.getTime();
+ }
+}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/web/controller/CloudAppController.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/web/controller/CloudAppController.java
index 10562b8..03aec3b 100644
--- a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/web/controller/CloudAppController.java
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/web/controller/CloudAppController.java
@@ -17,22 +17,16 @@
package org.apache.shardingsphere.elasticjob.cloud.ui.web.controller;
-import com.google.gson.JsonParseException;
-import org.apache.mesos.Protos.ExecutorID;
-import org.apache.mesos.Protos.SlaveID;
import org.apache.shardingsphere.elasticjob.cloud.config.pojo.CloudJobConfigurationPOJO;
-import org.apache.shardingsphere.elasticjob.cloud.scheduler.config.app.CloudAppConfigurationService;
-import org.apache.shardingsphere.elasticjob.cloud.scheduler.config.app.pojo.CloudAppConfigurationPOJO;
-import org.apache.shardingsphere.elasticjob.cloud.scheduler.config.job.CloudJobConfigurationService;
-import org.apache.shardingsphere.elasticjob.cloud.scheduler.exception.AppConfigurationException;
-import org.apache.shardingsphere.elasticjob.cloud.scheduler.mesos.MesosStateService;
-import org.apache.shardingsphere.elasticjob.cloud.scheduler.mesos.MesosStateService.ExecutorStateInfo;
-import org.apache.shardingsphere.elasticjob.cloud.scheduler.producer.ProducerManager;
-import org.apache.shardingsphere.elasticjob.cloud.scheduler.state.disable.app.DisableAppService;
+import org.apache.shardingsphere.elasticjob.cloud.ui.exception.AppConfigurationException;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.app.CloudAppConfigurationService;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.app.pojo.CloudAppConfigurationPOJO;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.job.CloudJobConfigurationService;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.producer.ProducerManager;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.state.disable.app.DisableAppService;
import org.apache.shardingsphere.elasticjob.cloud.ui.web.dto.CloudAppConfiguration;
import org.apache.shardingsphere.elasticjob.cloud.ui.web.response.ResponseResult;
import org.apache.shardingsphere.elasticjob.cloud.ui.web.response.ResponseResultUtil;
-import org.apache.shardingsphere.elasticjob.infra.exception.JobSystemException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
@@ -66,9 +60,6 @@ public final class CloudAppController {
@Autowired
private CloudJobConfigurationService jobConfigService;
- @Autowired
- private MesosStateService mesosStateService;
-
/**
* Register app config.
* @param appConfig cloud app config
@@ -131,11 +122,6 @@ public final class CloudAppController {
public ResponseResult disable(@PathVariable("appName") final String appName) {
if (appConfigService.load(appName).isPresent()) {
disableAppService.add(appName);
- for (CloudJobConfigurationPOJO each : jobConfigService.loadAll()) {
- if (appName.equals(each.getAppName())) {
- producerManager.unschedule(each.getJobName());
- }
- }
}
return ResponseResultUtil.success();
}
@@ -148,11 +134,6 @@ public final class CloudAppController {
public ResponseResult enable(@PathVariable("appName") final String appName) {
if (appConfigService.load(appName).isPresent()) {
disableAppService.remove(appName);
- for (CloudJobConfigurationPOJO each : jobConfigService.loadAll()) {
- if (appName.equals(each.getAppName())) {
- producerManager.reschedule(each.getJobName());
- }
- }
}
return ResponseResultUtil.success();
}
@@ -165,7 +146,6 @@ public final class CloudAppController {
public ResponseResult deregister(@PathVariable("appName") final String appName) {
if (appConfigService.load(appName).isPresent()) {
removeAppAndJobConfigurations(appName);
- stopExecutors(appName);
}
return ResponseResultUtil.success();
}
@@ -180,27 +160,14 @@ public final class CloudAppController {
appConfigService.remove(appName);
}
- private void stopExecutors(final String appName) {
- try {
- Collection<ExecutorStateInfo> executorBriefInfo = mesosStateService.executors(appName);
- for (ExecutorStateInfo each : executorBriefInfo) {
- producerManager.sendFrameworkMessage(ExecutorID.newBuilder().setValue(each.getId()).build(),
- SlaveID.newBuilder().setValue(each.getSlaveId()).build(),
- "STOP".getBytes());
- }
- } catch (final JsonParseException ex) {
- throw new JobSystemException(ex);
- }
- }
-
private Collection<CloudAppConfiguration> build(final Collection<CloudAppConfigurationPOJO> cloudAppConfigurationPOJOS) {
- return cloudAppConfigurationPOJOS.stream().map(this::convert).collect(Collectors.toList());
+ return cloudAppConfigurationPOJOS.stream().map(each -> convert(each)).collect(Collectors.toList());
}
private CloudAppConfiguration convert(final CloudAppConfigurationPOJO cloudAppConfigurationPOJO) {
- CloudAppConfiguration result = new CloudAppConfiguration();
- BeanUtils.copyProperties(cloudAppConfigurationPOJO, result);
- result.setDisabled(disableAppService.isDisabled(cloudAppConfigurationPOJO.getAppName()));
- return result;
+ CloudAppConfiguration cloudAppConfiguration = new CloudAppConfiguration();
+ BeanUtils.copyProperties(cloudAppConfigurationPOJO, cloudAppConfiguration);
+ cloudAppConfiguration.setDisabled(disableAppService.isDisabled(cloudAppConfigurationPOJO.getAppName()));
+ return cloudAppConfiguration;
}
}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/web/controller/CloudJobController.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/web/controller/CloudJobController.java
index 0170fdd..db8c440 100644
--- a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/web/controller/CloudJobController.java
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/web/controller/CloudJobController.java
@@ -21,17 +21,17 @@ import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.elasticjob.cloud.config.CloudJobExecutionType;
import org.apache.shardingsphere.elasticjob.cloud.config.pojo.CloudJobConfigurationPOJO;
-import org.apache.shardingsphere.elasticjob.cloud.scheduler.config.job.CloudJobConfigurationService;
-import org.apache.shardingsphere.elasticjob.cloud.scheduler.mesos.FacadeService;
-import org.apache.shardingsphere.elasticjob.cloud.scheduler.producer.ProducerManager;
-import org.apache.shardingsphere.elasticjob.cloud.scheduler.state.failover.FailoverTaskInfo;
-import org.apache.shardingsphere.elasticjob.cloud.scheduler.statistics.StatisticManager;
import org.apache.shardingsphere.elasticjob.cloud.statistics.StatisticInterval;
import org.apache.shardingsphere.elasticjob.cloud.statistics.type.job.JobExecutionTypeStatistics;
import org.apache.shardingsphere.elasticjob.cloud.statistics.type.job.JobRegisterStatistics;
import org.apache.shardingsphere.elasticjob.cloud.statistics.type.job.JobRunningStatistics;
import org.apache.shardingsphere.elasticjob.cloud.statistics.type.task.TaskResultStatistics;
import org.apache.shardingsphere.elasticjob.cloud.statistics.type.task.TaskRunningStatistics;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.FacadeService;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.job.CloudJobConfigurationService;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.producer.ProducerManager;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.state.failover.FailoverTaskInfo;
+import org.apache.shardingsphere.elasticjob.cloud.ui.service.statistics.StatisticManager;
import org.apache.shardingsphere.elasticjob.cloud.ui.web.controller.search.JobEventRdbSearch;
import org.apache.shardingsphere.elasticjob.cloud.ui.web.response.ResponseResult;
import org.apache.shardingsphere.elasticjob.cloud.ui.web.response.ResponseResultUtil;
@@ -138,7 +138,6 @@ public final class CloudJobController {
Optional<CloudJobConfigurationPOJO> configOptional = jobConfigService.load(jobName);
if (configOptional.isPresent()) {
facadeService.enableJob(jobName);
- producerManager.reschedule(jobName);
}
return ResponseResultUtil.build(Boolean.TRUE);
}
@@ -151,7 +150,6 @@ public final class CloudJobController {
public ResponseResult<Boolean> disable(@PathVariable("jobName") final String jobName) {
if (jobConfigService.load(jobName).isPresent()) {
facadeService.disableJob(jobName);
- producerManager.unschedule(jobName);
}
return ResponseResultUtil.build(Boolean.TRUE);
}
@@ -242,7 +240,7 @@ public final class CloudJobController {
@PostMapping("/events/executions")
public ResponseResult<JobEventRdbSearch.Result<JobExecutionEvent>> findJobExecutionEvents(@RequestParam final MultiValueMap<String, String> requestParams) throws ParseException {
if (!isRdbConfigured()) {
- return ResponseResultUtil.build(new JobEventRdbSearch.Result<>(0, Collections.emptyList()));
+ return ResponseResultUtil.build(new JobEventRdbSearch.Result<>(0, Collections.<JobExecutionEvent>emptyList()));
}
return ResponseResultUtil.build(jobEventRdbSearch.findJobExecutionEvents(buildCondition(requestParams, new String[]{"jobName", "taskId", "ip", "isSuccess"})));
}
@@ -256,7 +254,7 @@ public final class CloudJobController {
@PostMapping("/events/statusTraces")
public ResponseResult<JobEventRdbSearch.Result<JobStatusTraceEvent>> findJobStatusTraceEvents(@RequestParam final MultiValueMap<String, String> requestParams) throws ParseException {
if (!isRdbConfigured()) {
- return ResponseResultUtil.build(new JobEventRdbSearch.Result<>(0, Collections.emptyList()));
+ return ResponseResultUtil.build(new JobEventRdbSearch.Result<>(0, Collections.<JobStatusTraceEvent>emptyList()));
}
return ResponseResultUtil.build(jobEventRdbSearch.findJobStatusTraceEvents(buildCondition(requestParams, new String[]{"jobName", "taskId", "slaveId", "source", "executionType", "state"})));
}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/web/controller/CloudOperationController.java b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/web/controller/CloudOperationController.java
deleted file mode 100644
index c55808d..0000000
--- a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/cloud/ui/web/controller/CloudOperationController.java
+++ /dev/null
@@ -1,94 +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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.shardingsphere.elasticjob.cloud.ui.web.controller;
-
-import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
-import com.google.gson.JsonParseException;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.shardingsphere.elasticjob.cloud.scheduler.mesos.MesosStateService;
-import org.apache.shardingsphere.elasticjob.cloud.scheduler.mesos.ReconcileService;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.apache.shardingsphere.elasticjob.infra.exception.JobSystemException;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.util.Collection;
-import java.util.Map;
-
-/**
- * Cloud operation restful api.
- */
-@Slf4j
-@RestController
-@RequestMapping("/api/operate")
-public final class CloudOperationController {
-
- private static final long RECONCILE_MILLIS_INTERVAL = 10 * 1000L;
-
- private static long lastReconcileTime;
-
- @Autowired
- private ReconcileService reconcileService;
-
- @Autowired
- private MesosStateService mesosStateService;
-
- /**
- * Explicit reconcile service.
- */
- @PostMapping("/reconcile/explicit")
- public void explicitReconcile() {
- validReconcileInterval();
- reconcileService.explicitReconcile();
- }
-
- /**
- * Implicit reconcile service.
- */
- @PostMapping("/reconcile/implicit")
- public void implicitReconcile() {
- validReconcileInterval();
- reconcileService.implicitReconcile();
- }
-
- private void validReconcileInterval() {
- if (System.currentTimeMillis() < lastReconcileTime + RECONCILE_MILLIS_INTERVAL) {
- throw new RuntimeException("Repeat explicitReconcile");
- }
- lastReconcileTime = System.currentTimeMillis();
- }
-
- /**
- * Get sandbox of the cloud job by app name.
- * @param appName application name
- * @return sandbox info
- */
- @GetMapping("/sandbox")
- public Collection<Map<String, String>> sandbox(@RequestParam("appName") final String appName) {
- Preconditions.checkArgument(!Strings.isNullOrEmpty(appName), "Lack param 'appName'");
- try {
- return mesosStateService.sandbox(appName);
- } catch (final JsonParseException ex) {
- throw new JobSystemException(ex);
- }
- }
-}
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/resources/application.properties b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/resources/application.properties
index f31d024..c5b6436 100644
--- a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/resources/application.properties
+++ b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/resources/application.properties
@@ -21,3 +21,25 @@ auth.root_username=root
auth.root_password=root
auth.guest_username=guest
auth.guest_password=guest
+
+# ElasticJob-Cloud's zookeeper address
+zk.servers=127.0.0.1:2181
+
+# ElasticJob-Cloud's zookeeper namespace
+zk.namespace=elasticjob-cloud
+
+# ElasticJob-Cloud's zookeeper digest
+zk.digest=
+
+# Max size of job accumulated
+job.state.queue_size=10000
+
+# Event trace rdb config
+
+#event.trace.rdb_driver=com.mysql.jdbc.Driver
+
+#event.trace.rdb_url=jdbc:mysql://localhost:3306/elastic_job_cloud_log
+
+#event.trace.rdb_username=root
+
+#event.trace.rdb_password=
\ No newline at end of file
diff --git a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/resources/conf/elasticjob-cloud-scheduler.properties b/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/resources/conf/elasticjob-cloud-scheduler.properties
deleted file mode 100644
index 7e17d93..0000000
--- a/shardingsphere-elasticjob-cloud-ui/shardingsphere-elasticjob-cloud-ui-backend/src/main/resources/conf/elasticjob-cloud-scheduler.properties
+++ /dev/null
@@ -1,62 +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
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-# Routable IP address
-hostname=127.0.0.1
-
-# Username for mesos framework
-user=
-
-# Mesos zookeeper address
-mesos_url=zk://127.0.0.1:2181/mesos
-
-# Role for mesos framework
-
-#mesos_role=
-
-# ElasticJob-Cloud's zookeeper address
-zk_servers=127.0.0.1:2181
-
-# ElasticJob-Cloud's zookeeper namespace
-zk_namespace=elasticjob-cloud
-
-# ElasticJob-Cloud's zookeeper digest
-zk_digest=
-
-# Job rest API port
-http_port=8899
-
-# Max size of job accumulated
-job_state_queue_size=10000
-
-# Event trace rdb config
-
-#event_trace_rdb_driver=com.mysql.jdbc.Driver
-
-#event_trace_rdb_url=jdbc:mysql://localhost:3306/elastic_job_cloud_log
-
-#event_trace_rdb_username=root
-
-#event_trace_rdb_password=
-
-# Task reconciliation interval
-
-#reconcile_interval_minutes=-1
-
-# Enable/Disable mesos partition aware feature
-
-# enable_partition_aware=false
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-cloud-ui-bin-distribution/src/main/resources/application.properties b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-cloud-ui-bin-distribution/src/main/resources/application.properties
index ceff8ca..c5b6436 100644
--- a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-cloud-ui-bin-distribution/src/main/resources/application.properties
+++ b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-cloud-ui-bin-distribution/src/main/resources/application.properties
@@ -22,4 +22,24 @@ auth.root_password=root
auth.guest_username=guest
auth.guest_password=guest
+# ElasticJob-Cloud's zookeeper address
+zk.servers=127.0.0.1:2181
+# ElasticJob-Cloud's zookeeper namespace
+zk.namespace=elasticjob-cloud
+
+# ElasticJob-Cloud's zookeeper digest
+zk.digest=
+
+# Max size of job accumulated
+job.state.queue_size=10000
+
+# Event trace rdb config
+
+#event.trace.rdb_driver=com.mysql.jdbc.Driver
+
+#event.trace.rdb_url=jdbc:mysql://localhost:3306/elastic_job_cloud_log
+
+#event.trace.rdb_username=root
+
+#event.trace.rdb_password=
\ No newline at end of file
diff --git a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-cloud-ui-bin-distribution/src/main/resources/elasticjob-cloud-scheduler.properties b/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-cloud-ui-bin-distribution/src/main/resources/elasticjob-cloud-scheduler.properties
deleted file mode 100644
index 7e17d93..0000000
--- a/shardingsphere-elasticjob-ui-distribution/shardingsphere-elasticjob-cloud-ui-bin-distribution/src/main/resources/elasticjob-cloud-scheduler.properties
+++ /dev/null
@@ -1,62 +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
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-# Routable IP address
-hostname=127.0.0.1
-
-# Username for mesos framework
-user=
-
-# Mesos zookeeper address
-mesos_url=zk://127.0.0.1:2181/mesos
-
-# Role for mesos framework
-
-#mesos_role=
-
-# ElasticJob-Cloud's zookeeper address
-zk_servers=127.0.0.1:2181
-
-# ElasticJob-Cloud's zookeeper namespace
-zk_namespace=elasticjob-cloud
-
-# ElasticJob-Cloud's zookeeper digest
-zk_digest=
-
-# Job rest API port
-http_port=8899
-
-# Max size of job accumulated
-job_state_queue_size=10000
-
-# Event trace rdb config
-
-#event_trace_rdb_driver=com.mysql.jdbc.Driver
-
-#event_trace_rdb_url=jdbc:mysql://localhost:3306/elastic_job_cloud_log
-
-#event_trace_rdb_username=root
-
-#event_trace_rdb_password=
-
-# Task reconciliation interval
-
-#reconcile_interval_minutes=-1
-
-# Enable/Disable mesos partition aware feature
-
-# enable_partition_aware=false