diff --git a/README.md b/README.md
index bfcf5996..5800098a 100644
--- a/README.md
+++ b/README.md
@@ -47,7 +47,7 @@ PowerJob 的设计目标为企业级的分布式任务调度平台,即成为
| 在线任务治理 | 不支持 | 支持 | 支持 | **支持** |
| 日志白屏化 | 不支持 | 支持 | 不支持 | **支持** |
| 调度方式及性能 | 基于数据库锁,有性能瓶颈 | 基于数据库锁,有性能瓶颈 | 不详 | **无锁化设计,性能强劲无上限** |
-| 报警监控 | 无 | 邮件 | 短信 | **邮件与钉钉,并支持开发者扩展** |
+| 报警监控 | 无 | 邮件 | 短信 | **WebHook、邮件、钉钉与自定义扩展** |
| 系统依赖 | JDBC支持的关系型数据库(MySQL、Oracle...) | MySQL | 人民币 | **任意Spring Data Jpa支持的关系型数据库(MySQL、Oracle...)** |
| DAG工作流 | 不支持 | 不支持 | 支持 | **支持** |
diff --git a/README_enUS.md b/README_enUS.md
index aed3811c..badd96a8 100644
--- a/README_enUS.md
+++ b/README_enUS.md
@@ -9,26 +9,31 @@
-PowerJob is a powerful distributed scheduling platform and distributed computing framework based on Akka architecture.It provides you a chance to schedule job and distributed computing easily.
+- Have you ever wondered how cron jobs could be organized orderly?
+- Have you ever felt upset when scheduling tasks suddenly terminated without any warning?
+- Have you ever felt helpless when batches of business tasks require handling?
+- Have you ever felt depressed about tasks that carry with complex dependencies?
+
+Well, PowerJob is there for you, it is the choice of a new generation.It is a powerful, business-oriented scheduling framework that provides distributed computing ability.Based on Akka architecture, it makes everything with scheduling easier.Just with several steps, PowerJob could be deployed and work for you!
# Introduction
### Features
-- Simple to use: Provides a front-end Web interface that allows developers to visually complete the management of scheduled tasks (create, delete, update, and query), task operation status monitoring, and operation logs viewing.
-- Complete timing strategy: Support four timing scheduling strategies of CRON expression, fixed frequency, fixed delay and API.
-- Extensive execution modes: It supports four execution modes: stand-alone, broadcast, Map, and MapReduce. Among them, the Map / MapReduce processor enables developers to obtain cluster distributed computing capabilities with only a few lines of code.
-- Workflow(DAG) support: support online configuration of task dependencies, visually arrange tasks, as well as support for data transfer between upstream and downstream tasks
-- Extensive executor support: supports processors such as Spring Bean, ordinary Java objects, Shell, Python, and a wide range of applications (such as broadcast execution + Shell script to clear logs)
-- Convenient operation and maintenance: support online log function, the log generated by the actuator can be displayed on the front-end console page in real time, reduce the debugging cost, and greatly improve the development efficiency.
-- Dependency simplification: The smallest dependency-only database (MySQL / Oracle / MS SQLServer ...), the extended dependency is MongoDB (used to store huge online logs).
-- High availability & high performance: The scheduling server has been carefully designed to change the strategy of other scheduling frameworks based on database locks to achieve lock-free scheduling. Deploying multiple scheduling servers can achieve high availability and performance improvement at the same time (support unlimited horizontal expansion).
-- Failover and recovery: After the task fails to execute, the retry can be completed according to the configured retry strategy. As long as the executor cluster has enough computing nodes, the task can be successfully completed.
+- Simple to use: PowerJob provides a friendly front-end Web that allows developers to visually manage tasks (Create, Read, Update and Delete), monitor task status, and view operation logs online.
+- Complete timing strategy: PowerJob supports four different scheduling strategies, including CRON expression, fixed frequency timing, fixed delay timing as well as the Open API.
+- Various execution modes: PowerJob supports four execution modes: stand-alone, broadcast, Map, and MapReduce. It's worth mentioning the Map and MapReduce modes. With the completion of several lines of codes, developers could take full advantage of PowerJob's distributed computing ability.
+- Complete workflow support. PowerJob supports DAG(Directed acyclic graph) based online task configuration. Developers could arrange tasks on the console, while data could be transferred between tasks on the flow.
+- Extensive executor support: PowerJob supports multiple processors, including Spring Beans, ordinary Java objects, Shell, Python and so on.
+- Simple in dependency: PowerJob aims to be simple in dependency. The only dependency is merely database (MySQL / Oracle / MS SQLServer ...), with MongoDB being the extra dependency for storing huge online logs.
+- High availability and performance: Unlike traditional job-scheduling frameworks which rely on database locks, PowerJob server is lock-free when scheduling. PowerJob supports unlimited horizontal expansion. It's easy to achieve high availability and performance just by deploying as many PowerJob server instances as you need.
+- Quick failover and recovery support: Whenever any task failed, PowerJob server would retry according to the configured strategy. As long as there were enough nodes in the cluster, the failed tasks could execute successfully finally.
+- Convenient to run and maintain: PowerJob supports online logging. Logs generated by the worker would be transferred and displayed on the console instantly, therefore reducing the cost of debugging and improving the efficiency for developers significantly.
### Applicable scene
-- Business scenarios with regular execution requirements: such as synchronizing data in full volume every morning and generating business reports.
-- There are business scenarios that require all machines to perform together: such as log cleanup.
-- There are business scenarios that require distributed processing: for example, a large amount of data needs to be updated, and the stand-alone execution takes a long time. You can use the Map / MapReduce processors to complete the task distribution and mobilize the entire cluster to speed up the calculation.
+- Scenarios with timed tasks: such as full synchronization of data at midnight, generating business reports at desired time.
+- Scenarios that require all machines to run tasks simultaneously: such as log cleanup.
+- Scenarios that require distributed processing: For example, a large amount of data requires updating, while the stand-alone execution takes quite a lot of time. The Map/MapReduce mode could be applied while the workers would join the cluster for PowerJob server to dispatch, to speed up the time-consuming process, therefore improving the computing ablility of whole cluster.
### Comparison of similar products
@@ -36,14 +41,14 @@ PowerJob is a powerful distributed scheduling platform and distributed computing
| ---------------------------------- | --------------------------------------------------------- | --------------------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| Timing type | CRON | CRON | CRON, fixed frequency, fixed delay, OpenAPI | **CRON, fixed frequency, fixed delay, OpenAPI** |
| Task type | Built-in Java | Built-in Java, GLUE Java, Shell, Python and other scripts | Built-in Java, external Java (FatJar), Shell, Python and other scripts | **Built-in Java, external Java (container), Shell, Python and other scripts** |
-| Distributed task | no | Static sharding | MapReduce dynamic sharding | **MapReduce dynamic sharding** |
-| Online task governance | not support | support | support | **support** |
-| Log blanking | not support | support | not support | **support** |
+| Distributed strategy | Unsupported | Static sharding | MapReduce dynamic sharding | **MapReduce dynamic sharding** |
+| Online task management | Unsupported | Supported | Supported | **Supported** |
+| Online logging | Unsupported | Supported | Unsupported | **Supported** |
| Scheduling methods and performance | Based on database lock, there is a performance bottleneck | Based on database lock, there is a performance bottleneck | Unknown | **Lock-free design, powerful performance without upper limit** |
-| Alarm monitoring | no | mail | SMS | **Email, providing an interface to allow developers to customize development** |
-| System dependence | Any relational database (MySQL, Oracle ...) supported by JDBC | MySQL | Renminbi (free during public beta, hey, help to advertise) | **Any relational database (MySQL, Oracle ...) supported by Spring Data Jpa** |
-| workflow | not support | not support | support | **support** |
-
+| Alarm monitoring | Unsupported | Email | SMS | **Email, WebHook, Dingtalk. An interface is provided for customization.** |
+| System dependence | Any relational database (MySQL, Oracle ...) supported by JDBC | MySQL | RMB (free during public beta, hey, help to advertise) | **Any relational database (MySQL, Oracle ...) supported by Spring Data Jpa** |
+| workflow | Unsupported | Unsupported | Supported | **Supported** |
+
# Document
**[GitHub Wiki](https://github.com/KFCFans/PowerJob/wiki)**
@@ -51,7 +56,8 @@ PowerJob is a powerful distributed scheduling platform and distributed computing
# Others
-- The product is permanently open source (Apache License, Version 2.0), free to use, and the current developer @KFCFans has sufficient time to maintain the project and provide free technical support (All of my time), welcome to try!
-- Welcome to participate in the contribution of this project, PR and Issue are greatly welcome (please) ~
-- If you feel pretty good, you can give it a star to support it ~ =  ̄ω ̄ =
-- Need some help or have some advice? Welcome to contact Developer @KFCFans-> `tengjiqi@gmail.com`
\ No newline at end of file
+- PowerJob is permanently open source software(Apache License, Version 2.0), please feel free to try, use or deploy!
+- Owner of PowerJob (@KFCFans) has abundant time for maintenance, and is willing to provide technical support if you have needs!
+- Welcome to contribute to PowerJob, both Pull Requests and Issues are precious.
+- Please STAR PowerJob if it is valuable. ~ =  ̄ω ̄ =
+- Do you need any help or want to propose suggestions? Please raise Github issues or contact the Author @KFCFans-> `tengjiqi@gmail.com` directly.
\ No newline at end of file
diff --git a/others/images/user.png b/others/images/user.png
index 8de90911..fd3da626 100644
Binary files a/others/images/user.png and b/others/images/user.png differ
diff --git a/others/oms-sql.sql b/others/oms-sql.sql
index cc029c33..234f8865 100644
--- a/others/oms-sql.sql
+++ b/others/oms-sql.sql
@@ -5,13 +5,13 @@
Source Server Type : MySQL
Source Server Version : 80021
Source Host : localhost:3306
- Source Schema : powerjob-daily
+ Source Schema : powerjob-db-template
Target Server Type : MySQL
Target Server Version : 80021
File Encoding : 65001
- Date: 08/10/2020 12:39:10
+ Date: 28/11/2020 17:05:50
*/
SET NAMES utf8mb4;
@@ -30,7 +30,7 @@ CREATE TABLE `app_info` (
`password` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `appNameUK` (`app_name`)
-) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- ----------------------------
-- Table structure for container_info
@@ -77,7 +77,7 @@ CREATE TABLE `instance_info` (
KEY `IDX5b1nhpe5je7gc5s1ur200njr7` (`job_id`),
KEY `IDXjnji5lrr195kswk6f7mfhinrs` (`app_id`),
KEY `IDXa98hq3yu0l863wuotdjl7noum` (`instance_id`)
-) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- ----------------------------
-- Table structure for job_info
@@ -111,7 +111,7 @@ CREATE TABLE `job_info` (
`time_expression_type` int DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `IDXk2xprmn3lldmlcb52i36udll1` (`app_id`)
-) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- ----------------------------
-- Table structure for oms_lock
@@ -126,7 +126,7 @@ CREATE TABLE `oms_lock` (
`ownerip` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `lockNameUK` (`lock_name`)
-) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- ----------------------------
-- Table structure for server_info
@@ -148,12 +148,12 @@ DROP TABLE IF EXISTS `user_info`;
CREATE TABLE `user_info` (
`id` bigint NOT NULL AUTO_INCREMENT,
`email` varchar(255) DEFAULT NULL,
+ `extra` varchar(255) DEFAULT NULL,
`gmt_create` datetime(6) DEFAULT NULL,
`gmt_modified` datetime(6) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
`phone` varchar(255) DEFAULT NULL,
`username` varchar(255) DEFAULT NULL,
- `extra` varchar(255) DEFAULT NULL,
`web_hook` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
@@ -178,7 +178,7 @@ CREATE TABLE `workflow_info` (
`wf_name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `IDX7uo5w0e3beeho3fnx9t7eiol3` (`app_id`)
-) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- ----------------------------
-- Table structure for workflow_instance_info
@@ -189,6 +189,7 @@ CREATE TABLE `workflow_instance_info` (
`actual_trigger_time` bigint DEFAULT NULL,
`app_id` bigint DEFAULT NULL,
`dag` longtext,
+ `expected_trigger_time` bigint DEFAULT NULL,
`finished_time` bigint DEFAULT NULL,
`gmt_create` datetime(6) DEFAULT NULL,
`gmt_modified` datetime(6) DEFAULT NULL,
@@ -198,6 +199,6 @@ CREATE TABLE `workflow_instance_info` (
`wf_instance_id` bigint DEFAULT NULL,
`workflow_id` bigint DEFAULT NULL,
PRIMARY KEY (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
SET FOREIGN_KEY_CHECKS = 1;
diff --git a/powerjob-client/pom.xml b/powerjob-client/pom.xml
index 2fa776a5..ac7d0292 100644
--- a/powerjob-client/pom.xml
+++ b/powerjob-client/pom.xml
@@ -10,13 +10,13 @@
4.0.0
powerjob-client
- 3.3.3
+ 3.4.0
jar
5.6.1
1.2.68
- 3.3.3
+ 3.4.0
3.2.4
diff --git a/powerjob-common/pom.xml b/powerjob-common/pom.xml
index b28c9717..29436f48 100644
--- a/powerjob-common/pom.xml
+++ b/powerjob-common/pom.xml
@@ -10,7 +10,7 @@
4.0.0
powerjob-common
- 3.3.3
+ 3.4.0
jar
diff --git a/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/SystemInstanceResult.java b/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/SystemInstanceResult.java
index 0682a94d..5f53fecc 100644
--- a/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/SystemInstanceResult.java
+++ b/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/SystemInstanceResult.java
@@ -11,7 +11,7 @@ public class SystemInstanceResult {
/* *********** 普通instance 专用 *********** */
// 同时运行的任务实例数过多
- public static final String TOO_MUCH_INSTANCE = "too much instance(%d>%d)";
+ public static final String TOO_MANY_INSTANCES = "too many instances(%d>%d)";
// 无可用worker
public static final String NO_WORKER_AVAILABLE = "no worker available";
// 任务执行超时
diff --git a/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/WorkflowInstanceStatus.java b/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/WorkflowInstanceStatus.java
index 4a2a1e6f..7bba8d25 100644
--- a/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/WorkflowInstanceStatus.java
+++ b/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/WorkflowInstanceStatus.java
@@ -24,7 +24,8 @@ public enum WorkflowInstanceStatus {
// 广义的运行状态
public static final List generalizedRunningStatus = Lists.newArrayList(WAITING.v, RUNNING.v);
-
+ // 结束状态
+ public static final List finishedStatus = Lists.newArrayList(FAILED.v, SUCCEED.v, STOPPED.v);
private int v;
private String des;
diff --git a/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/response/WorkflowInstanceInfoDTO.java b/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/response/WorkflowInstanceInfoDTO.java
index c9a22df4..b35ea919 100644
--- a/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/response/WorkflowInstanceInfoDTO.java
+++ b/powerjob-common/src/main/java/com/github/kfcfans/powerjob/common/response/WorkflowInstanceInfoDTO.java
@@ -27,6 +27,8 @@ public class WorkflowInstanceInfoDTO {
private String dag;
private String result;
+ // 预计触发时间
+ private Long expectedTriggerTime;
// 实际触发时间
private Long actualTriggerTime;
// 结束时间
diff --git a/powerjob-server/pom.xml b/powerjob-server/pom.xml
index 480559c7..68036a10 100644
--- a/powerjob-server/pom.xml
+++ b/powerjob-server/pom.xml
@@ -10,13 +10,13 @@
4.0.0
powerjob-server
- 3.3.3
+ 3.4.0
jar
2.9.2
2.3.4.RELEASE
- 3.3.3
+ 3.4.0
8.0.19
19.7.0.0
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/common/RejectedExecutionHandlerFactory.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/common/RejectedExecutionHandlerFactory.java
new file mode 100644
index 00000000..691dee87
--- /dev/null
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/common/RejectedExecutionHandlerFactory.java
@@ -0,0 +1,58 @@
+package com.github.kfcfans.powerjob.server.common;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.concurrent.RejectedExecutionHandler;
+
+/**
+ * 拒绝策略
+ *
+ * @author tjq
+ * @since 2020/11/28
+ */
+@Slf4j
+public class RejectedExecutionHandlerFactory {
+
+ /**
+ * 直接丢弃该任务
+ * @param source log name
+ * @return A handler for tasks that cannot be executed by ThreadPool
+ */
+ public static RejectedExecutionHandler newReject(String source) {
+ return (r, p) -> {
+ log.error("[{}] ThreadPool[{}] overload, the task[{}] will be dropped!", source, p, r);
+ log.warn("[{}] Maybe you need to adjust the ThreadPool config!", source);
+ };
+ }
+
+ /**
+ * 调用线程运行
+ * @param source log name
+ * @return A handler for tasks that cannot be executed by ThreadPool
+ */
+ public static RejectedExecutionHandler newCallerRun(String source) {
+ return (r, p) -> {
+ log.warn("[{}] ThreadPool[{}] overload, the task[{}] will run by caller thread!", source, p, r);
+ log.warn("[{}] Maybe you need to adjust the ThreadPool config!", source);
+ if (!p.isShutdown()) {
+ r.run();
+ }
+ };
+ }
+
+ /**
+ * 新线程运行
+ * @param source log name
+ * @return A handler for tasks that cannot be executed by ThreadPool
+ */
+ public static RejectedExecutionHandler newThreadRun(String source) {
+ return (r, p) -> {
+ log.warn("[{}] ThreadPool[{}] overload, the task[{}] will run by a new thread!", source, p, r);
+ log.warn("[{}] Maybe you need to adjust the ThreadPool config!", source);
+ if (!p.isShutdown()) {
+ new Thread(r).start();
+ }
+ };
+ }
+
+}
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/common/config/ThreadPoolConfig.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/common/config/ThreadPoolConfig.java
index 5597eaf5..5762f0ce 100644
--- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/common/config/ThreadPoolConfig.java
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/common/config/ThreadPoolConfig.java
@@ -1,5 +1,6 @@
package com.github.kfcfans.powerjob.server.common.config;
+import com.github.kfcfans.powerjob.server.common.RejectedExecutionHandlerFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -33,11 +34,7 @@ public class ThreadPoolConfig {
executor.setQueueCapacity(0);
executor.setKeepAliveSeconds(60);
executor.setThreadNamePrefix("omsTimingPool-");
- executor.setRejectedExecutionHandler((r, e) -> {
- log.warn("[OmsTimingService] timing pool can't schedule job immediately, maybe some job using too much cpu times.");
- // 定时任务优先级较高,不惜一些代价都需要继续执行,开线程继续干~
- new Thread(r).start();
- });
+ executor.setRejectedExecutionHandler(RejectedExecutionHandlerFactory.newThreadRun("PowerJobTimingPool"));
return executor;
}
@@ -49,7 +46,7 @@ public class ThreadPoolConfig {
executor.setQueueCapacity(8192);
executor.setKeepAliveSeconds(60);
executor.setThreadNamePrefix("omsBackgroundPool-");
- executor.setRejectedExecutionHandler(new LogOnRejected());
+ executor.setRejectedExecutionHandler(RejectedExecutionHandlerFactory.newReject("PowerJobBackgroundPool"));
return executor;
}
@@ -63,11 +60,4 @@ public class ThreadPoolConfig {
return scheduler;
}
- private static final class LogOnRejected implements RejectedExecutionHandler {
-
- @Override
- public void rejectedExecution(Runnable r, ThreadPoolExecutor p) {
- log.error("[OmsThreadPool] Task({}) rejected from pool({}).", r, p);
- }
- }
}
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/common/utils/timewheel/HashedWheelTimer.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/common/utils/timewheel/HashedWheelTimer.java
index 847966a1..241bbe5d 100644
--- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/common/utils/timewheel/HashedWheelTimer.java
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/common/utils/timewheel/HashedWheelTimer.java
@@ -1,6 +1,7 @@
package com.github.kfcfans.powerjob.server.common.utils.timewheel;
import com.github.kfcfans.powerjob.common.utils.CommonUtils;
+import com.github.kfcfans.powerjob.server.common.RejectedExecutionHandlerFactory;
import com.google.common.collect.Queues;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
@@ -66,9 +67,9 @@ public class HashedWheelTimer implements Timer {
ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("HashedWheelTimer-Executor-%d").build();
BlockingQueue queue = Queues.newLinkedBlockingQueue(16);
int core = Math.max(Runtime.getRuntime().availableProcessors(), processThreadNum);
- taskProcessPool = new ThreadPoolExecutor(core, 2 * core,
+ taskProcessPool = new ThreadPoolExecutor(core, 4 * core,
60, TimeUnit.SECONDS,
- queue, threadFactory, new ThreadPoolExecutor.CallerRunsPolicy());
+ queue, threadFactory, RejectedExecutionHandlerFactory.newCallerRun("PowerJobTimeWheelPool"));
}
startTime = System.currentTimeMillis();
@@ -172,6 +173,11 @@ public class HashedWheelTimer implements Timer {
removeIf(timerFuture -> {
+ // processCanceledTasks 后外部操作取消任务会导致 BUCKET 中仍存在 CANCELED 任务的情况
+ if (timerFuture.status == HashedWheelTimerFuture.CANCELED) {
+ return true;
+ }
+
if (timerFuture.status != HashedWheelTimerFuture.WAITING) {
log.warn("[HashedWheelTimer] impossible, please fix the bug");
return true;
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/persistence/core/model/WorkflowInstanceInfoDO.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/persistence/core/model/WorkflowInstanceInfoDO.java
index c2a074a4..e6f483c4 100644
--- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/persistence/core/model/WorkflowInstanceInfoDO.java
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/persistence/core/model/WorkflowInstanceInfoDO.java
@@ -48,6 +48,8 @@ public class WorkflowInstanceInfoDO {
@Column
private String result;
+ // 预计触发时间
+ private Long expectedTriggerTime;
// 实际触发时间
private Long actualTriggerTime;
// 结束时间
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/persistence/core/repository/InstanceInfoRepository.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/persistence/core/repository/InstanceInfoRepository.java
index f65fb299..3742e3c8 100644
--- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/persistence/core/repository/InstanceInfoRepository.java
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/persistence/core/repository/InstanceInfoRepository.java
@@ -71,6 +71,6 @@ public interface InstanceInfoRepository extends JpaRepository status);
}
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/persistence/core/repository/WorkflowInstanceInfoRepository.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/persistence/core/repository/WorkflowInstanceInfoRepository.java
index 809bfdfc..6dabc143 100644
--- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/persistence/core/repository/WorkflowInstanceInfoRepository.java
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/persistence/core/repository/WorkflowInstanceInfoRepository.java
@@ -24,11 +24,11 @@ public interface WorkflowInstanceInfoRepository extends JpaRepository status);
int countByWorkflowIdAndStatusIn(Long workflowId, List status);
// 状态检查
- List findByAppIdInAndStatusAndGmtModifiedBefore(List appIds, int status, Date before);
+ List findByAppIdInAndStatusAndExpectedTriggerTimeLessThan(List appIds, int status, long time);
}
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/DispatchService.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/DispatchService.java
index d92c7a01..8f98c7a0 100644
--- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/DispatchService.java
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/DispatchService.java
@@ -84,7 +84,7 @@ public class DispatchService {
long runningInstanceCount = instanceInfoRepository.countByJobIdAndStatusIn(jobId, Lists.newArrayList(WAITING_WORKER_RECEIVE.getV(), RUNNING.getV()));
// 超出最大同时运行限制,不执行调度
if (runningInstanceCount > maxInstanceNum) {
- String result = String.format(SystemInstanceResult.TOO_MUCH_INSTANCE, runningInstanceCount, maxInstanceNum);
+ String result = String.format(SystemInstanceResult.TOO_MANY_INSTANCES, runningInstanceCount, maxInstanceNum);
log.warn("[Dispatcher-{}|{}] cancel dispatch job due to too much instance is running ({} > {}).", jobId, instanceId, runningInstanceCount, maxInstanceNum);
instanceInfoRepository.update4TriggerFailed(instanceId, FAILED.getV(), currentRunningTimes, current, current, RemoteConstant.EMPTY_ADDRESS, result, dbInstanceParams, now);
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/ValidateService.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/ValidateService.java
new file mode 100644
index 00000000..742ecfee
--- /dev/null
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/ValidateService.java
@@ -0,0 +1,71 @@
+package com.github.kfcfans.powerjob.server.service;
+
+import com.github.kfcfans.powerjob.common.OmsConstant;
+import com.github.kfcfans.powerjob.common.TimeExpressionType;
+import com.github.kfcfans.powerjob.server.common.utils.CronExpression;
+import com.google.common.collect.Lists;
+import org.apache.commons.lang3.time.DateFormatUtils;
+
+import java.text.ParseException;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 校验服务
+ *
+ * @author tjq
+ * @since 2020/11/28
+ */
+public class ValidateService {
+
+ private static final int NEXT_N_TIMES = 5;
+
+ /**
+ * 计算指定时间表达式接下来的运行状况
+ * @param timeExpressionType 时间表达式类型
+ * @param timeExpression 时间表达式
+ * @return 最近 N 次运行的时间
+ * @throws Exception 异常
+ */
+ public static List calculateNextTriggerTime(TimeExpressionType timeExpressionType, String timeExpression) throws Exception {
+ switch (timeExpressionType) {
+ case API: return Lists.newArrayList(OmsConstant.NONE);
+ case WORKFLOW: return Lists.newArrayList("VALID: depends on workflow");
+ case CRON: return calculateCronExpression(timeExpression);
+ case FIX_RATE: return calculateFixRate(timeExpression);
+ case FIX_DELAY: return Lists.newArrayList("VALID: depends on execution cost time");
+ }
+ // impossible
+ return Collections.emptyList();
+ }
+
+
+ private static List calculateFixRate(String timeExpression) {
+ List result = Lists.newArrayList();
+ long delay = Long.parseLong(timeExpression);
+ for (int i = 0; i < NEXT_N_TIMES; i++) {
+ long nextTime = System.currentTimeMillis() + i * delay;
+ result.add(DateFormatUtils.format(nextTime, OmsConstant.TIME_PATTERN));
+ }
+ return result;
+ }
+
+ private static List calculateCronExpression(String expression) throws ParseException {
+ CronExpression cronExpression = new CronExpression(expression);
+ List result = Lists.newArrayList();
+ Date time = new Date();
+ for (int i = 0; i < NEXT_N_TIMES; i++) {
+ Date nextValidTime = cronExpression.getNextValidTimeAfter(time);
+ if (nextValidTime == null) {
+ break;
+ }
+ result.add(DateFormatUtils.format(nextValidTime.getTime(), OmsConstant.TIME_PATTERN));
+ time = nextValidTime;
+ }
+ if (result.isEmpty()) {
+ result.add("INVALID: no next validate schedule time");
+ }
+ return result;
+ }
+}
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/instance/InstanceTimeWheelService.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/instance/InstanceTimeWheelService.java
index 10a0c9d3..c4e626c9 100644
--- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/instance/InstanceTimeWheelService.java
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/instance/InstanceTimeWheelService.java
@@ -18,10 +18,15 @@ public class InstanceTimeWheelService {
private static final Map CARGO = Maps.newConcurrentMap();
- // 精确时间轮,每 1S 走一格
+ // 精确调度时间轮,每 1MS 走一格
private static final HashedWheelTimer TIMER = new HashedWheelTimer(1, 4096, Runtime.getRuntime().availableProcessors() * 4);
+ // 非精确调度时间轮,用于处理高延迟任务,每 10S 走一格
+ private static final HashedWheelTimer SLOW_TIMER = new HashedWheelTimer(10000, 12, 0);
+
// 支持取消的时间间隔,低于该阈值则不会放进 CARGO
private static final long MIN_INTERVAL_MS = 1000;
+ // 长延迟阈值
+ private static final long LONG_DELAY_THRESHOLD_MS = 60000;
/**
* 定时调度
@@ -30,13 +35,17 @@ public class InstanceTimeWheelService {
* @param timerTask 需要执行的目标方法
*/
public static void schedule(Long uniqueId, Long delayMS, TimerTask timerTask) {
- TimerFuture timerFuture = TIMER.schedule(() -> {
- CARGO.remove(uniqueId);
- timerTask.run();
- }, delayMS, TimeUnit.MILLISECONDS);
- if (delayMS > MIN_INTERVAL_MS) {
- CARGO.put(uniqueId, timerFuture);
+ if (delayMS <= LONG_DELAY_THRESHOLD_MS) {
+ realSchedule(uniqueId, delayMS, timerTask);
+ return;
}
+
+ long expectTriggerTime = System.currentTimeMillis() + delayMS;
+ TimerFuture longDelayTask = SLOW_TIMER.schedule(() -> {
+ CARGO.remove(uniqueId);
+ realSchedule(uniqueId, expectTriggerTime - System.currentTimeMillis(), timerTask);
+ }, delayMS - LONG_DELAY_THRESHOLD_MS, TimeUnit.MILLISECONDS);
+ CARGO.put(uniqueId, longDelayTask);
}
/**
@@ -48,4 +57,15 @@ public class InstanceTimeWheelService {
return CARGO.get(uniqueId);
}
+
+ private static void realSchedule(Long uniqueId, Long delayMS, TimerTask timerTask) {
+ TimerFuture timerFuture = TIMER.schedule(() -> {
+ CARGO.remove(uniqueId);
+ timerTask.run();
+ }, delayMS, TimeUnit.MILLISECONDS);
+ if (delayMS > MIN_INTERVAL_MS) {
+ CARGO.put(uniqueId, timerFuture);
+ }
+ }
+
}
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/timing/CleanService.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/timing/CleanService.java
index da429f08..f180ce3d 100644
--- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/timing/CleanService.java
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/timing/CleanService.java
@@ -1,5 +1,7 @@
package com.github.kfcfans.powerjob.server.service.timing;
+import com.github.kfcfans.powerjob.common.InstanceStatus;
+import com.github.kfcfans.powerjob.common.WorkflowInstanceStatus;
import com.github.kfcfans.powerjob.server.common.utils.OmsFileUtils;
import com.github.kfcfans.powerjob.server.persistence.core.repository.InstanceInfoRepository;
import com.github.kfcfans.powerjob.server.persistence.core.repository.WorkflowInstanceInfoRepository;
@@ -128,7 +130,7 @@ public class CleanService {
}
try {
Date t = DateUtils.addDays(new Date(), -instanceInfoRetentionDay);
- int num = instanceInfoRepository.deleteAllByGmtModifiedBefore(t);
+ int num = instanceInfoRepository.deleteAllByGmtModifiedBeforeAndStatusIn(t, InstanceStatus.finishedStatus);
log.info("[CleanService] deleted {} instanceInfo records whose modify time before {}.", num, t);
}catch (Exception e) {
log.warn("[CleanService] clean instanceInfo failed.", e);
@@ -142,7 +144,7 @@ public class CleanService {
}
try {
Date t = DateUtils.addDays(new Date(), -instanceInfoRetentionDay);
- int num = workflowInstanceInfoRepository.deleteAllByGmtModifiedBefore(t);
+ int num = workflowInstanceInfoRepository.deleteAllByGmtModifiedBeforeAndStatusIn(t, WorkflowInstanceStatus.finishedStatus);
log.info("[CleanService] deleted {} workflow instanceInfo records whose modify time before {}.", num, t);
}catch (Exception e) {
log.warn("[CleanService] clean workflow instanceInfo failed.", e);
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/timing/InstanceStatusCheckService.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/timing/InstanceStatusCheckService.java
index 489f2874..ddea791e 100644
--- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/timing/InstanceStatusCheckService.java
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/timing/InstanceStatusCheckService.java
@@ -162,7 +162,7 @@ public class InstanceStatusCheckService {
// 重试长时间处于 WAITING 状态的工作流实例
long threshold = System.currentTimeMillis() - WORKFLOW_WAITING_TIMEOUT_MS;
Lists.partition(allAppIds, MAX_BATCH_NUM).forEach(partAppIds -> {
- List waitingWfInstanceList = workflowInstanceInfoRepository.findByAppIdInAndStatusAndGmtModifiedBefore(partAppIds, WorkflowInstanceStatus.WAITING.getV(), new Date(threshold));
+ List waitingWfInstanceList = workflowInstanceInfoRepository.findByAppIdInAndStatusAndExpectedTriggerTimeLessThan(partAppIds, WorkflowInstanceStatus.WAITING.getV(), threshold);
if (!CollectionUtils.isEmpty(waitingWfInstanceList)) {
List wfInstanceIds = waitingWfInstanceList.stream().map(WorkflowInstanceInfoDO::getWfInstanceId).collect(Collectors.toList());
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/timing/schedule/OmsScheduleService.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/timing/schedule/OmsScheduleService.java
index 2115a664..f036b374 100644
--- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/timing/schedule/OmsScheduleService.java
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/timing/schedule/OmsScheduleService.java
@@ -193,7 +193,7 @@ public class OmsScheduleService {
wfInfos.forEach(wfInfo -> {
// 1. 先生成调度记录,防止不调度的情况发生
- Long wfInstanceId = workflowInstanceManager.create(wfInfo, null);
+ Long wfInstanceId = workflowInstanceManager.create(wfInfo, null, wfInfo.getNextTriggerTime());
// 2. 推入时间轮,准备调度执行
long delay = wfInfo.getNextTriggerTime() - System.currentTimeMillis();
@@ -220,6 +220,9 @@ public class OmsScheduleService {
try {
// 查询所有的秒级任务(只包含ID)
List jobIds = jobInfoRepository.findByAppIdInAndStatusAndTimeExpressionTypeIn(partAppIds, SwitchableStatus.ENABLE.getV(), TimeExpressionType.frequentTypes);
+ if (CollectionUtils.isEmpty(jobIds)) {
+ return;
+ }
// 查询日志记录表中是否存在相关的任务
List runningJobIdList = instanceInfoRepository.findByJobIdInAndStatusIn(jobIds, InstanceStatus.generalizedRunningStatus);
Set runningJobIdSet = Sets.newHashSet(runningJobIdList);
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/workflow/WorkflowInstanceManager.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/workflow/WorkflowInstanceManager.java
index 37ca9396..a10b8a92 100644
--- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/workflow/WorkflowInstanceManager.java
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/workflow/WorkflowInstanceManager.java
@@ -68,9 +68,10 @@ public class WorkflowInstanceManager {
* 创建工作流任务实例
* @param wfInfo 工作流任务元数据(描述信息)
* @param initParams 启动参数
+ * @param expectTriggerTime 预计执行时间
* @return wfInstanceId
*/
- public Long create(WorkflowInfoDO wfInfo, String initParams) {
+ public Long create(WorkflowInfoDO wfInfo, String initParams, Long expectTriggerTime) {
Long wfId = wfInfo.getId();
Long wfInstanceId = idGenerateService.allocate();
@@ -82,6 +83,7 @@ public class WorkflowInstanceManager {
newWfInstance.setWfInstanceId(wfInstanceId);
newWfInstance.setWorkflowId(wfId);
newWfInstance.setStatus(WorkflowInstanceStatus.WAITING.getV());
+ newWfInstance.setExpectedTriggerTime(expectTriggerTime);
newWfInstance.setActualTriggerTime(System.currentTimeMillis());
newWfInstance.setWfInitParams(initParams);
@@ -129,7 +131,7 @@ public class WorkflowInstanceManager {
// 并发度控制
int instanceConcurrency = workflowInstanceInfoRepository.countByWorkflowIdAndStatusIn(wfInfo.getId(), WorkflowInstanceStatus.generalizedRunningStatus);
if (instanceConcurrency > wfInfo.getMaxWfInstanceNum()) {
- onWorkflowInstanceFailed(String.format(SystemInstanceResult.TOO_MUCH_INSTANCE, instanceConcurrency, wfInfo.getMaxWfInstanceNum()), wfInstanceInfo);
+ onWorkflowInstanceFailed(String.format(SystemInstanceResult.TOO_MANY_INSTANCES, instanceConcurrency, wfInfo.getMaxWfInstanceNum()), wfInstanceInfo);
return;
}
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/workflow/WorkflowService.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/workflow/WorkflowService.java
index 51929452..53ae028b 100644
--- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/workflow/WorkflowService.java
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/service/workflow/WorkflowService.java
@@ -168,7 +168,7 @@ public class WorkflowService {
private Long realRunWorkflow(WorkflowInfoDO wfInfo, String initParams, long delay) {
log.info("[WorkflowService-{}] try to run workflow, initParams={},delay={} ms.", wfInfo.getId(), initParams, delay);
- Long wfInstanceId = workflowInstanceManager.create(wfInfo, initParams);
+ Long wfInstanceId = workflowInstanceManager.create(wfInfo, initParams, System.currentTimeMillis() + delay);
if (delay <= 0) {
workflowInstanceManager.start(wfInfo, wfInstanceId, initParams);
}else {
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/ControllerExceptionHandler.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/ControllerExceptionHandler.java
index 54c3e75e..92506dc2 100644
--- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/ControllerExceptionHandler.java
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/ControllerExceptionHandler.java
@@ -3,6 +3,7 @@ package com.github.kfcfans.powerjob.server.web;
import com.github.kfcfans.powerjob.common.PowerJobException;
import com.github.kfcfans.powerjob.common.response.ResultDTO;
import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.messaging.handler.annotation.support.MethodArgumentTypeMismatchException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
@@ -34,6 +35,6 @@ public class ControllerExceptionHandler {
} else {
log.error("[ControllerException] http request failed.", e);
}
- return ResultDTO.failed(e.getMessage());
+ return ResultDTO.failed(ExceptionUtils.getMessage(e));
}
}
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/controller/ValidateController.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/controller/ValidateController.java
new file mode 100644
index 00000000..cb9b122e
--- /dev/null
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/controller/ValidateController.java
@@ -0,0 +1,32 @@
+package com.github.kfcfans.powerjob.server.web.controller;
+
+import com.github.kfcfans.powerjob.common.TimeExpressionType;
+import com.github.kfcfans.powerjob.common.response.ResultDTO;
+import com.github.kfcfans.powerjob.server.service.ValidateService;
+import com.google.common.collect.Lists;
+import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * 校验控制器
+ *
+ * @author tjq
+ * @since 2020/11/28
+ */
+@RestController
+@RequestMapping("/validate")
+public class ValidateController {
+
+ @GetMapping("/timeExpression")
+ public ResultDTO> checkTimeExpression(TimeExpressionType timeExpressionType, String timeExpression) {
+ try {
+ return ResultDTO.success(ValidateService.calculateNextTriggerTime(timeExpressionType, timeExpression));
+ } catch (Exception e) {
+ return ResultDTO.success(Lists.newArrayList(ExceptionUtils.getMessage(e)));
+ }
+ }
+}
diff --git a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/response/WorkflowInstanceInfoVO.java b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/response/WorkflowInstanceInfoVO.java
index 20c55b06..1524a848 100644
--- a/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/response/WorkflowInstanceInfoVO.java
+++ b/powerjob-server/src/main/java/com/github/kfcfans/powerjob/server/web/response/WorkflowInstanceInfoVO.java
@@ -32,6 +32,8 @@ public class WorkflowInstanceInfoVO {
private PEWorkflowDAG pEWorkflowDAG;
private String result;
+ // 预计触发时间
+ private String expectedTriggerTime;
// 实际触发时间(需要格式化为人看得懂的时间)
private String actualTriggerTime;
// 结束时间(同理,需要格式化)
@@ -49,6 +51,9 @@ public class WorkflowInstanceInfoVO {
vo.setWorkflowId(String.valueOf(wfInstanceDO.getWorkflowId()));
// 格式化时间
+ if (wfInstanceDO.getExpectedTriggerTime() != null) {
+ vo.setExpectedTriggerTime(DateFormatUtils.format(wfInstanceDO.getExpectedTriggerTime(), OmsConstant.TIME_PATTERN));
+ }
vo.setActualTriggerTime(DateFormatUtils.format(wfInstanceDO.getActualTriggerTime(), OmsConstant.TIME_PATTERN));
if (wfInstanceDO.getFinishedTime() == null) {
vo.setFinishedTime(OmsConstant.NONE);
diff --git a/powerjob-server/src/main/resources/logback-product.xml b/powerjob-server/src/main/resources/logback-product.xml
index 9f63badf..2be6e263 100644
--- a/powerjob-server/src/main/resources/logback-product.xml
+++ b/powerjob-server/src/main/resources/logback-product.xml
@@ -2,18 +2,17 @@
+
+
+
+
+
-
-
- ${CONSOLE_LOG_PATTERN}
- utf8
-
-
diff --git a/powerjob-server/src/main/resources/static/js/10.js b/powerjob-server/src/main/resources/static/js/10.js
index df7d7196..76514e9c 100644
--- a/powerjob-server/src/main/resources/static/js/10.js
+++ b/powerjob-server/src/main/resources/static/js/10.js
@@ -1,62 +1,96 @@
(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[10],{
-/***/ "./node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/views/JobManager.vue?vue&type=script&lang=js&":
-/*!*************************************************************************************************************************************************************************************************************************************************************!*\
- !*** ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/views/JobManager.vue?vue&type=script&lang=js& ***!
- \*************************************************************************************************************************************************************************************************************************************************************/
+/***/ "./node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/views/WFInstanceManager.vue?vue&type=script&lang=js&":
+/*!********************************************************************************************************************************************************************************************************************************************************************!*\
+ !*** ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/views/WFInstanceManager.vue?vue&type=script&lang=js& ***!
+ \********************************************************************************************************************************************************************************************************************************************************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
-eval("__webpack_require__.r(__webpack_exports__);\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n name: \"JobManager\",\n data: function data() {\n return {\n modifiedJobFormVisible: false,\n // 新建任务对象\n modifiedJobForm: {\n id: undefined,\n jobName: \"\",\n jobDescription: \"\",\n appId: this.$store.state.appInfo.id,\n jobParams: \"\",\n timeExpressionType: \"\",\n timeExpression: \"\",\n executeType: \"\",\n processorType: \"\",\n processorInfo: \"\",\n maxInstanceNum: 0,\n concurrency: 5,\n instanceTimeLimit: 0,\n instanceRetryNum: 0,\n taskRetryNum: 1,\n minCpuCores: 0,\n minMemorySpace: 0,\n minDiskSpace: 0,\n enable: true,\n designatedWorkers: \"\",\n maxWorkerCount: 0,\n notifyUserIds: []\n },\n // 任务查询请求对象\n jobQueryContent: {\n appId: this.$store.state.appInfo.id,\n index: 0,\n pageSize: 10,\n jobId: undefined,\n keyword: undefined\n },\n // 任务列表(查询结果),包含index、pageSize、totalPages、totalItems、data(List类型)\n jobInfoPageResult: {\n pageSize: 10,\n totalItems: 0,\n data: []\n },\n // 时间表达式选择类型\n timeExpressionTypeOptions: [{\n key: \"API\",\n label: \"API\"\n }, {\n key: \"CRON\",\n label: \"CRON\"\n }, {\n key: \"FIX_RATE\",\n label: this.$t('message.fixRate')\n }, {\n key: \"FIX_DELAY\",\n label: this.$t('message.fixDelay')\n }, {\n key: \"WORKFLOW\",\n label: this.$t('message.workflow')\n }],\n // 处理器类型\n processorTypeOptions: [{\n key: \"EMBEDDED_JAVA\",\n label: \"JAVA\"\n }, {\n key: \"JAVA_CONTAINER\",\n label: this.$t('message.javaContainer')\n }, {\n key: \"SHELL\",\n label: \"SHELL\"\n }, {\n key: \"PYTHON\",\n label: \"PYTHON\"\n }],\n // 执行方式类型\n executeTypeOptions: [{\n key: \"STANDALONE\",\n label: this.$t('message.standalone')\n }, {\n key: \"BROADCAST\",\n label: this.$t('message.broadcast')\n }, {\n key: \"MAP\",\n label: this.$t('message.map')\n }, {\n key: \"MAP_REDUCE\",\n label: this.$t('message.mapReduce')\n }],\n // 用户列表\n userList: []\n };\n },\n methods: {\n // 保存变更,包括新增和修改\n saveJob: function saveJob() {\n var _this = this;\n\n var that = this;\n this.axios.post(\"/job/save\", this.modifiedJobForm).then(function () {\n that.modifiedJobFormVisible = false;\n that.$message.success(_this.$t('message.success')); // 重新加载数据\n\n that.listJobInfos();\n }, function () {\n return that.modifiedJobFormVisible = false;\n });\n },\n // 列出符合当前搜索条件的任务\n listJobInfos: function listJobInfos() {\n var that = this;\n this.axios.post(\"/job/list\", this.jobQueryContent).then(function (res) {\n that.jobInfoPageResult = res;\n });\n },\n // 修改任务状态\n changeJobStatus: function changeJobStatus(data) {\n // switch 会自动更改 enable 的值\n var that = this;\n\n if (data.enable === false) {\n // 仅有,有特殊逻辑(关闭秒级任务),走单独接口\n that.axios.get(\"/job/disable?jobId=\" + data.id).then(function () {\n return that.listJobInfos();\n });\n } else {\n // 启用,则发起正常的保存操作\n this.modifiedJobForm = data;\n this.saveJob();\n }\n },\n // 新增任务,去除旧数据\n onClickNewJob: function onClickNewJob() {\n this.modifiedJobForm.id = undefined;\n this.modifiedJobForm.jobName = undefined;\n this.modifiedJobForm.jobDescription = undefined;\n this.modifiedJobForm.jobParams = undefined;\n this.modifiedJobForm.timeExpression = undefined;\n this.modifiedJobForm.timeExpressionType = undefined;\n this.modifiedJobForm.processorInfo = undefined;\n this.modifiedJobForm.processorType = undefined;\n this.modifiedJobForm.executeType = undefined;\n this.modifiedJobFormVisible = true;\n },\n // 点击 编辑按钮\n onClickModify: function onClickModify(data) {\n // 修复点击编辑后再点击新增 行数据被清空 的问题\n this.modifiedJobForm = JSON.parse(JSON.stringify(data));\n this.modifiedJobFormVisible = true;\n },\n // 点击 立即运行按钮\n onClickRun: function onClickRun(data) {\n var _this2 = this;\n\n var that = this;\n var url = \"/job/run?jobId=\" + data.id;\n this.axios.get(url).then(function () {\n return that.$message.success(_this2.$t('message.success'));\n });\n },\n // 点击 删除任务\n onClickDeleteJob: function onClickDeleteJob(data) {\n var _this3 = this;\n\n var that = this;\n var url = \"/job/delete?jobId=\" + data.id;\n this.axios.get(url).then(function () {\n that.$message.success(_this3.$t('message.success'));\n that.listJobInfos();\n });\n },\n // 点击 历史记录\n onClickRunHistory: function onClickRunHistory(data) {\n console.log(JSON.stringify(data));\n this.$router.push({\n name: 'instanceManager',\n params: {\n jobId: data.id\n }\n });\n },\n // 点击 换页\n onClickChangePage: function onClickChangePage(index) {\n // 后端从0开始,前端从1开始\n this.jobQueryContent.index = index - 1;\n this.listJobInfos();\n },\n // 点击重置按钮\n onClickReset: function onClickReset() {\n this.jobQueryContent.keyword = undefined;\n this.jobQueryContent.jobId = undefined;\n this.listJobInfos();\n },\n verifyPlaceholder: function verifyPlaceholder(processorType) {\n var res;\n\n switch (processorType) {\n case \"EMBEDDED_JAVA\":\n res = this.$t('message.javaProcessorInfoPLH');\n break;\n\n case \"JAVA_CONTAINER\":\n res = this.$t('message.containerProcessorInfoPLH');\n break;\n\n case \"SHELL\":\n res = this.$t('message.shellProcessorInfoPLH');\n break;\n\n case \"PYTHON\":\n res = this.$t('message.pythonProcessorInfoPLH');\n }\n\n return res;\n },\n // 翻译执行类型\n translateExecuteType: function translateExecuteType(executeType) {\n switch (executeType) {\n case \"STANDALONE\":\n return this.$t('message.standalone');\n\n case \"BROADCAST\":\n return this.$t('message.broadcast');\n\n case \"MAP_REDUCE\":\n return this.$t('message.mapReduce');\n\n case \"MAP\":\n return this.$t('message.map');\n\n default:\n return \"UNKNOWN\";\n }\n },\n // 翻译处理器类型\n translateProcessorType: function translateProcessorType(processorType) {\n if (processorType === \"JAVA_CONTAINER\") {\n return this.$t('message.javaContainer');\n }\n\n return processorType;\n }\n },\n mounted: function mounted() {\n // 加载用户信息\n var that = this;\n that.axios.get(\"/user/list\").then(function (res) {\n return that.userList = res;\n }); // 加载任务信息\n\n this.listJobInfos();\n }\n});\n\n//# sourceURL=webpack:///./src/components/views/JobManager.vue?./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options");
+eval("__webpack_require__.r(__webpack_exports__);\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n name: \"WFInstanceManager\",\n data: function data() {\n return {\n // 查询条件\n wfInstanceQueryContent: {\n appId: this.$store.state.appInfo.id,\n index: 0,\n pageSize: 10,\n wfInstanceId: undefined,\n workflowId: undefined,\n status: \"\"\n },\n // 查询结果\n wfInstancePageResult: {\n pageSize: 10,\n totalItems: 0,\n data: []\n },\n // 工作流实例状态选择\n wfInstanceStatusOptions: [{\n key: \"\",\n label: this.$t('message.all')\n }, {\n key: \"WAITING\",\n label: this.$t('message.waitingDispatch')\n }, {\n key: \"RUNNING\",\n label: this.$t('message.running')\n }, {\n key: \"FAILED\",\n label: this.$t('message.failed')\n }, {\n key: \"SUCCEED\",\n label: this.$t('message.success')\n }, {\n key: \"STOPPED\",\n label: this.$t('message.stopped')\n }]\n };\n },\n methods: {\n listWfInstances: function listWfInstances() {\n var that = this;\n this.axios.post(\"/wfInstance/list\", this.wfInstanceQueryContent).then(function (res) {\n return that.wfInstancePageResult = res;\n });\n },\n // 重置搜索条件\n onClickRest: function onClickRest() {\n this.wfInstanceQueryContent.wfInstanceId = undefined;\n this.wfInstanceQueryContent.workflowId = undefined;\n this.wfInstanceQueryContent.status = \"\";\n this.listWfInstances();\n },\n // 查看工作流详情\n onClickShowDetail: function onClickShowDetail(data) {\n console.log(data);\n this.$router.push({\n name: 'WorkflowInstanceDetail',\n params: {\n wfInstanceId: data.wfInstanceId\n }\n });\n },\n // 停止工作流\n onClickStop: function onClickStop(data) {\n var _this = this;\n\n var that = this;\n var url = \"/wfInstance/stop?wfInstanceId=\" + data.wfInstanceId + \"&appId=\" + this.$store.state.appInfo.id;\n this.axios.get(url).then(function () {\n that.$message.success(_this.$t('message.success')); // 重新加载列表\n\n that.listInstanceInfos();\n });\n },\n // 换页\n onClickChangeInstancePage: function onClickChangeInstancePage(index) {\n // 后端从0开始,前端从1开始\n this.wfInstanceQueryContent.index = index - 1;\n this.listWfInstances();\n },\n // 表单颜色\n wfInstanceTableRowClassName: function wfInstanceTableRowClassName(_ref) {\n var row = _ref.row;\n\n switch (row.status) {\n // 失败\n case 3:\n return \"error-row\";\n // 成功\n\n case 4:\n return \"success-row\";\n\n case 10:\n return \"warning-row\";\n }\n },\n fetchWFStatus: function fetchWFStatus(status) {\n return this.common.translateWfInstanceStatus(status);\n }\n },\n mounted: function mounted() {\n this.listWfInstances();\n }\n});\n\n//# sourceURL=webpack:///./src/components/views/WFInstanceManager.vue?./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options");
/***/ }),
-/***/ "./node_modules/cache-loader/dist/cjs.js?{\"cacheDirectory\":\"node_modules/.cache/vue-loader\",\"cacheIdentifier\":\"f7b44cbc-vue-loader-template\"}!./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/views/JobManager.vue?vue&type=template&id=392659be&scoped=true&":
-/*!*********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\
- !*** ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"f7b44cbc-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/views/JobManager.vue?vue&type=template&id=392659be&scoped=true& ***!
- \*********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
+/***/ "./node_modules/cache-loader/dist/cjs.js?{\"cacheDirectory\":\"node_modules/.cache/vue-loader\",\"cacheIdentifier\":\"f7b44cbc-vue-loader-template\"}!./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/views/WFInstanceManager.vue?vue&type=template&id=bfc76970&":
+/*!****************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\
+ !*** ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"f7b44cbc-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/views/WFInstanceManager.vue?vue&type=template&id=bfc76970& ***!
+ \****************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
/*! exports provided: render, staticRenderFns */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
-eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"render\", function() { return render; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"staticRenderFns\", function() { return staticRenderFns; });\nvar render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\n \"div\",\n { attrs: { id: \"job_manager\" } },\n [\n _c(\n \"el-row\",\n { attrs: { gutter: 20 } },\n [\n _c(\n \"el-col\",\n { attrs: { span: 20 } },\n [\n _c(\n \"el-form\",\n {\n staticClass: \"el-form--inline\",\n attrs: { inline: true, model: _vm.jobQueryContent }\n },\n [\n _c(\n \"el-form-item\",\n { attrs: { label: _vm.$t(\"message.jobId\") } },\n [\n _c(\"el-input\", {\n attrs: { placeholder: _vm.$t(\"message.jobId\") },\n model: {\n value: _vm.jobQueryContent.jobId,\n callback: function($$v) {\n _vm.$set(_vm.jobQueryContent, \"jobId\", $$v)\n },\n expression: \"jobQueryContent.jobId\"\n }\n })\n ],\n 1\n ),\n _c(\n \"el-form-item\",\n { attrs: { label: _vm.$t(\"message.keyword\") } },\n [\n _c(\"el-input\", {\n attrs: { placeholder: _vm.$t(\"message.keyword\") },\n model: {\n value: _vm.jobQueryContent.keyword,\n callback: function($$v) {\n _vm.$set(_vm.jobQueryContent, \"keyword\", $$v)\n },\n expression: \"jobQueryContent.keyword\"\n }\n })\n ],\n 1\n ),\n _c(\n \"el-form-item\",\n [\n _c(\n \"el-button\",\n {\n attrs: { type: \"primary\" },\n on: { click: _vm.listJobInfos }\n },\n [_vm._v(_vm._s(_vm.$t(\"message.query\")))]\n ),\n _c(\n \"el-button\",\n {\n attrs: { type: \"cancel\" },\n on: { click: _vm.onClickReset }\n },\n [_vm._v(_vm._s(_vm.$t(\"message.reset\")))]\n )\n ],\n 1\n )\n ],\n 1\n )\n ],\n 1\n ),\n _c(\"el-col\", { attrs: { span: 4 } }, [\n _c(\n \"div\",\n { staticStyle: { float: \"right\", \"padding-right\": \"10px\" } },\n [\n _c(\n \"el-button\",\n {\n attrs: { type: \"primary\" },\n on: { click: _vm.onClickNewJob }\n },\n [_vm._v(_vm._s(_vm.$t(\"message.newJob\")))]\n )\n ],\n 1\n )\n ])\n ],\n 1\n ),\n _c(\n \"el-row\",\n [\n _c(\n \"el-table\",\n {\n staticStyle: { width: \"100%\" },\n attrs: { data: _vm.jobInfoPageResult.data }\n },\n [\n _c(\"el-table-column\", {\n attrs: {\n prop: \"id\",\n label: _vm.$t(\"message.jobId\"),\n width: \"80\"\n }\n }),\n _c(\"el-table-column\", {\n attrs: { prop: \"jobName\", label: _vm.$t(\"message.jobName\") }\n }),\n _c(\"el-table-column\", {\n attrs: { label: _vm.$t(\"message.scheduleInfo\") },\n scopedSlots: _vm._u([\n {\n key: \"default\",\n fn: function(scope) {\n return [\n _vm._v(\n \" \" +\n _vm._s(scope.row.timeExpressionType) +\n \" \" +\n _vm._s(scope.row.timeExpression) +\n \" \"\n )\n ]\n }\n }\n ])\n }),\n _c(\"el-table-column\", {\n attrs: { label: _vm.$t(\"message.executeType\") },\n scopedSlots: _vm._u([\n {\n key: \"default\",\n fn: function(scope) {\n return [\n _vm._v(\n \" \" +\n _vm._s(\n _vm.translateExecuteType(scope.row.executeType)\n ) +\n \" \"\n )\n ]\n }\n }\n ])\n }),\n _c(\"el-table-column\", {\n attrs: { label: _vm.$t(\"message.processorType\") },\n scopedSlots: _vm._u([\n {\n key: \"default\",\n fn: function(scope) {\n return [\n _vm._v(\n \" \" +\n _vm._s(\n _vm.translateProcessorType(\n scope.row.processorType\n )\n ) +\n \" \"\n )\n ]\n }\n }\n ])\n }),\n _c(\"el-table-column\", {\n attrs: { label: _vm.$t(\"message.status\"), width: \"80\" },\n scopedSlots: _vm._u([\n {\n key: \"default\",\n fn: function(scope) {\n return [\n _c(\"el-switch\", {\n attrs: {\n \"active-color\": \"#13ce66\",\n \"inactive-color\": \"#ff4949\"\n },\n on: {\n change: function($event) {\n return _vm.changeJobStatus(scope.row)\n }\n },\n model: {\n value: scope.row.enable,\n callback: function($$v) {\n _vm.$set(scope.row, \"enable\", $$v)\n },\n expression: \"scope.row.enable\"\n }\n })\n ]\n }\n }\n ])\n }),\n _c(\"el-table-column\", {\n attrs: { label: _vm.$t(\"message.operation\"), width: \"150\" },\n scopedSlots: _vm._u([\n {\n key: \"default\",\n fn: function(scope) {\n return [\n _c(\n \"el-button\",\n {\n attrs: { size: \"mini\", type: \"text\" },\n on: {\n click: function($event) {\n return _vm.onClickModify(scope.row)\n }\n }\n },\n [_vm._v(_vm._s(_vm.$t(\"message.edit\")))]\n ),\n _c(\n \"el-button\",\n {\n attrs: { size: \"mini\", type: \"text\" },\n on: {\n click: function($event) {\n return _vm.onClickRun(scope.row)\n }\n }\n },\n [_vm._v(_vm._s(_vm.$t(\"message.run\")))]\n ),\n _c(\n \"el-dropdown\",\n { attrs: { trigger: \"click\" } },\n [\n _c(\n \"el-button\",\n { attrs: { size: \"mini\", type: \"text\" } },\n [_vm._v(_vm._s(_vm.$t(\"message.more\")))]\n ),\n _c(\n \"el-dropdown-menu\",\n { attrs: { slot: \"dropdown\" }, slot: \"dropdown\" },\n [\n _c(\n \"el-dropdown-item\",\n [\n _c(\n \"el-button\",\n {\n attrs: { size: \"mini\", type: \"text\" },\n on: {\n click: function($event) {\n return _vm.onClickRunHistory(\n scope.row\n )\n }\n }\n },\n [\n _vm._v(\n _vm._s(_vm.$t(\"message.runHistory\"))\n )\n ]\n )\n ],\n 1\n ),\n _c(\n \"el-dropdown-item\",\n [\n _c(\n \"el-button\",\n {\n attrs: { size: \"mini\", type: \"text\" },\n on: {\n click: function($event) {\n return _vm.onClickDeleteJob(\n scope.row\n )\n }\n }\n },\n [_vm._v(_vm._s(_vm.$t(\"message.delete\")))]\n )\n ],\n 1\n )\n ],\n 1\n )\n ],\n 1\n )\n ]\n }\n }\n ])\n })\n ],\n 1\n )\n ],\n 1\n ),\n _c(\n \"el-row\",\n [\n _c(\"el-pagination\", {\n attrs: {\n layout: \"prev, pager, next\",\n total: this.jobInfoPageResult.totalItems,\n \"page-size\": this.jobInfoPageResult.pageSize,\n \"hide-on-single-page\": true\n },\n on: { \"current-change\": _vm.onClickChangePage }\n })\n ],\n 1\n ),\n _c(\n \"el-dialog\",\n {\n attrs: { visible: _vm.modifiedJobFormVisible, width: \"60%\" },\n on: {\n \"update:visible\": function($event) {\n _vm.modifiedJobFormVisible = $event\n }\n }\n },\n [\n _c(\n \"el-form\",\n { attrs: { model: _vm.modifiedJobForm, \"label-width\": \"120px\" } },\n [\n _c(\n \"el-form-item\",\n { attrs: { label: _vm.$t(\"message.jobName\") } },\n [\n _c(\"el-input\", {\n model: {\n value: _vm.modifiedJobForm.jobName,\n callback: function($$v) {\n _vm.$set(_vm.modifiedJobForm, \"jobName\", $$v)\n },\n expression: \"modifiedJobForm.jobName\"\n }\n })\n ],\n 1\n ),\n _c(\n \"el-form-item\",\n { attrs: { label: _vm.$t(\"message.jobDescription\") } },\n [\n _c(\"el-input\", {\n model: {\n value: _vm.modifiedJobForm.jobDescription,\n callback: function($$v) {\n _vm.$set(_vm.modifiedJobForm, \"jobDescription\", $$v)\n },\n expression: \"modifiedJobForm.jobDescription\"\n }\n })\n ],\n 1\n ),\n _c(\n \"el-form-item\",\n { attrs: { label: _vm.$t(\"message.jobParams\") } },\n [\n _c(\"el-input\", {\n model: {\n value: _vm.modifiedJobForm.jobParams,\n callback: function($$v) {\n _vm.$set(_vm.modifiedJobForm, \"jobParams\", $$v)\n },\n expression: \"modifiedJobForm.jobParams\"\n }\n })\n ],\n 1\n ),\n _c(\n \"el-form-item\",\n { attrs: { label: _vm.$t(\"message.scheduleInfo\") } },\n [\n _c(\n \"el-row\",\n [\n _c(\n \"el-col\",\n { attrs: { span: 8 } },\n [\n _c(\n \"el-select\",\n {\n attrs: {\n placeholder: _vm.$t(\n \"message.timeExpressionType\"\n )\n },\n model: {\n value: _vm.modifiedJobForm.timeExpressionType,\n callback: function($$v) {\n _vm.$set(\n _vm.modifiedJobForm,\n \"timeExpressionType\",\n $$v\n )\n },\n expression: \"modifiedJobForm.timeExpressionType\"\n }\n },\n _vm._l(_vm.timeExpressionTypeOptions, function(\n item\n ) {\n return _c(\"el-option\", {\n key: item.key,\n attrs: { label: item.label, value: item.key }\n })\n }),\n 1\n )\n ],\n 1\n ),\n _c(\n \"el-col\",\n { attrs: { span: 12 } },\n [\n _c(\"el-input\", {\n attrs: {\n placeholder: _vm.$t(\n \"message.timeExpressionPlaceHolder\"\n )\n },\n model: {\n value: _vm.modifiedJobForm.timeExpression,\n callback: function($$v) {\n _vm.$set(\n _vm.modifiedJobForm,\n \"timeExpression\",\n $$v\n )\n },\n expression: \"modifiedJobForm.timeExpression\"\n }\n })\n ],\n 1\n ),\n _c(\n \"el-col\",\n { attrs: { span: 4 } },\n [\n _c(\n \"el-link\",\n {\n attrs: {\n href: \"https://www.bejson.com/othertools/cron/\",\n type: \"success\",\n target: \"_blank\"\n }\n },\n [_vm._v(_vm._s(_vm.$t(\"message.onlineCronTool\")))]\n )\n ],\n 1\n )\n ],\n 1\n )\n ],\n 1\n ),\n _c(\n \"el-form-item\",\n { attrs: { label: _vm.$t(\"message.executeConfig\") } },\n [\n _c(\n \"el-row\",\n [\n _c(\n \"el-col\",\n { attrs: { span: 5 } },\n [\n _c(\n \"el-select\",\n {\n attrs: {\n placeholder: _vm.$t(\"message.executeType\")\n },\n model: {\n value: _vm.modifiedJobForm.executeType,\n callback: function($$v) {\n _vm.$set(\n _vm.modifiedJobForm,\n \"executeType\",\n $$v\n )\n },\n expression: \"modifiedJobForm.executeType\"\n }\n },\n _vm._l(_vm.executeTypeOptions, function(item) {\n return _c(\"el-option\", {\n key: item.key,\n attrs: { label: item.label, value: item.key }\n })\n }),\n 1\n )\n ],\n 1\n ),\n _c(\n \"el-col\",\n { attrs: { span: 6 } },\n [\n _c(\n \"el-select\",\n {\n attrs: {\n placeholder: _vm.$t(\"message.processorType\")\n },\n model: {\n value: _vm.modifiedJobForm.processorType,\n callback: function($$v) {\n _vm.$set(\n _vm.modifiedJobForm,\n \"processorType\",\n $$v\n )\n },\n expression: \"modifiedJobForm.processorType\"\n }\n },\n _vm._l(_vm.processorTypeOptions, function(item) {\n return _c(\"el-option\", {\n key: item.key,\n attrs: { label: item.label, value: item.key }\n })\n }),\n 1\n )\n ],\n 1\n ),\n _c(\n \"el-col\",\n { attrs: { span: 13 } },\n [\n _c(\"el-input\", {\n attrs: {\n placeholder: _vm.verifyPlaceholder(\n _vm.modifiedJobForm.processorType\n )\n },\n model: {\n value: _vm.modifiedJobForm.processorInfo,\n callback: function($$v) {\n _vm.$set(\n _vm.modifiedJobForm,\n \"processorInfo\",\n $$v\n )\n },\n expression: \"modifiedJobForm.processorInfo\"\n }\n })\n ],\n 1\n )\n ],\n 1\n )\n ],\n 1\n ),\n _c(\n \"el-form-item\",\n { attrs: { label: _vm.$t(\"message.runtimeConfig\") } },\n [\n _c(\n \"el-row\",\n [\n _c(\n \"el-col\",\n { attrs: { span: 8 } },\n [\n _c(\n \"el-input\",\n {\n staticClass: \"ruleContent\",\n attrs: {\n placeholder: _vm.$t(\"message.maxInstanceNum\")\n },\n model: {\n value: _vm.modifiedJobForm.maxInstanceNum,\n callback: function($$v) {\n _vm.$set(\n _vm.modifiedJobForm,\n \"maxInstanceNum\",\n $$v\n )\n },\n expression: \"modifiedJobForm.maxInstanceNum\"\n }\n },\n [\n _c(\"template\", { slot: \"prepend\" }, [\n _vm._v(_vm._s(_vm.$t(\"message.maxInstanceNum\")))\n ])\n ],\n 2\n )\n ],\n 1\n ),\n _c(\n \"el-col\",\n { attrs: { span: 8 } },\n [\n _c(\n \"el-input\",\n {\n staticClass: \"ruleContent\",\n attrs: {\n placeholder: _vm.$t(\"message.threadConcurrency\")\n },\n model: {\n value: _vm.modifiedJobForm.concurrency,\n callback: function($$v) {\n _vm.$set(\n _vm.modifiedJobForm,\n \"concurrency\",\n $$v\n )\n },\n expression: \"modifiedJobForm.concurrency\"\n }\n },\n [\n _c(\"template\", { slot: \"prepend\" }, [\n _vm._v(\n _vm._s(_vm.$t(\"message.threadConcurrency\"))\n )\n ])\n ],\n 2\n )\n ],\n 1\n ),\n _c(\n \"el-col\",\n { attrs: { span: 8 } },\n [\n _c(\n \"el-input\",\n {\n staticClass: \"ruleContent\",\n attrs: { placeholder: _vm.$t(\"message.timeout\") },\n model: {\n value: _vm.modifiedJobForm.instanceTimeLimit,\n callback: function($$v) {\n _vm.$set(\n _vm.modifiedJobForm,\n \"instanceTimeLimit\",\n $$v\n )\n },\n expression: \"modifiedJobForm.instanceTimeLimit\"\n }\n },\n [\n _c(\"template\", { slot: \"prepend\" }, [\n _vm._v(_vm._s(_vm.$t(\"message.timeout\")))\n ])\n ],\n 2\n )\n ],\n 1\n )\n ],\n 1\n )\n ],\n 1\n ),\n _c(\n \"el-form-item\",\n { attrs: { label: _vm.$t(\"message.retryConfig\") } },\n [\n _c(\n \"el-row\",\n [\n _c(\n \"el-col\",\n { attrs: { span: 12 } },\n [\n _c(\n \"el-input\",\n {\n staticClass: \"ruleContent\",\n attrs: {\n placeholder: _vm.$t(\"message.taskRetryTimes\")\n },\n model: {\n value: _vm.modifiedJobForm.instanceRetryNum,\n callback: function($$v) {\n _vm.$set(\n _vm.modifiedJobForm,\n \"instanceRetryNum\",\n $$v\n )\n },\n expression: \"modifiedJobForm.instanceRetryNum\"\n }\n },\n [\n _c(\"template\", { slot: \"prepend\" }, [\n _vm._v(_vm._s(_vm.$t(\"message.taskRetryTimes\")))\n ])\n ],\n 2\n )\n ],\n 1\n ),\n _c(\n \"el-col\",\n { attrs: { span: 12 } },\n [\n _c(\n \"el-input\",\n {\n staticClass: \"ruleContent\",\n attrs: {\n placeholder: _vm.$t(\"message.subTaskRetryTimes\")\n },\n model: {\n value: _vm.modifiedJobForm.taskRetryNum,\n callback: function($$v) {\n _vm.$set(\n _vm.modifiedJobForm,\n \"taskRetryNum\",\n $$v\n )\n },\n expression: \"modifiedJobForm.taskRetryNum\"\n }\n },\n [\n _c(\"template\", { slot: \"prepend\" }, [\n _vm._v(\n _vm._s(_vm.$t(\"message.subTaskRetryTimes\"))\n )\n ])\n ],\n 2\n )\n ],\n 1\n )\n ],\n 1\n )\n ],\n 1\n ),\n _c(\n \"el-form-item\",\n { attrs: { label: _vm.$t(\"message.workerConfig\") } },\n [\n _c(\n \"el-row\",\n [\n _c(\n \"el-col\",\n { attrs: { span: 8 } },\n [\n _c(\n \"el-input\",\n {\n staticClass: \"ruleContent\",\n attrs: { placeholder: _vm.$t(\"message.minCPU\") },\n model: {\n value: _vm.modifiedJobForm.minCpuCores,\n callback: function($$v) {\n _vm.$set(\n _vm.modifiedJobForm,\n \"minCpuCores\",\n $$v\n )\n },\n expression: \"modifiedJobForm.minCpuCores\"\n }\n },\n [\n _c(\"template\", { slot: \"prepend\" }, [\n _vm._v(_vm._s(_vm.$t(\"message.minCPU\")))\n ])\n ],\n 2\n )\n ],\n 1\n ),\n _c(\n \"el-col\",\n { attrs: { span: 8 } },\n [\n _c(\n \"el-input\",\n {\n staticClass: \"ruleContent\",\n attrs: {\n placeholder: _vm.$t(\"message.minMemory\")\n },\n model: {\n value: _vm.modifiedJobForm.minMemorySpace,\n callback: function($$v) {\n _vm.$set(\n _vm.modifiedJobForm,\n \"minMemorySpace\",\n $$v\n )\n },\n expression: \"modifiedJobForm.minMemorySpace\"\n }\n },\n [\n _c(\"template\", { slot: \"prepend\" }, [\n _vm._v(_vm._s(_vm.$t(\"message.minMemory\")))\n ])\n ],\n 2\n )\n ],\n 1\n ),\n _c(\n \"el-col\",\n { attrs: { span: 8 } },\n [\n _c(\n \"el-input\",\n {\n staticClass: \"ruleContent\",\n attrs: { placeholder: _vm.$t(\"message.minDisk\") },\n model: {\n value: _vm.modifiedJobForm.minDiskSpace,\n callback: function($$v) {\n _vm.$set(\n _vm.modifiedJobForm,\n \"minDiskSpace\",\n $$v\n )\n },\n expression: \"modifiedJobForm.minDiskSpace\"\n }\n },\n [\n _c(\"template\", { slot: \"prepend\" }, [\n _vm._v(_vm._s(_vm.$t(\"message.minDisk\")))\n ])\n ],\n 2\n )\n ],\n 1\n )\n ],\n 1\n )\n ],\n 1\n ),\n _c(\n \"el-form-item\",\n { attrs: { label: _vm.$t(\"message.clusterConfig\") } },\n [\n _c(\n \"el-row\",\n [\n _c(\n \"el-col\",\n { attrs: { span: 16 } },\n [\n _c(\n \"el-input\",\n {\n staticClass: \"ruleContent\",\n attrs: {\n placeholder: _vm.$t(\n \"message.designatedWorkerAddressPLH\"\n )\n },\n model: {\n value: _vm.modifiedJobForm.designatedWorkers,\n callback: function($$v) {\n _vm.$set(\n _vm.modifiedJobForm,\n \"designatedWorkers\",\n $$v\n )\n },\n expression: \"modifiedJobForm.designatedWorkers\"\n }\n },\n [\n _c(\"template\", { slot: \"prepend\" }, [\n _vm._v(\n _vm._s(\n _vm.$t(\"message.designatedWorkerAddress\")\n )\n )\n ])\n ],\n 2\n )\n ],\n 1\n ),\n _c(\n \"el-col\",\n { attrs: { span: 8 } },\n [\n _c(\n \"el-input\",\n {\n staticClass: \"ruleContent\",\n attrs: {\n placeholder: _vm.$t(\"message.maxWorkerNumPLH\")\n },\n model: {\n value: _vm.modifiedJobForm.maxWorkerCount,\n callback: function($$v) {\n _vm.$set(\n _vm.modifiedJobForm,\n \"maxWorkerCount\",\n $$v\n )\n },\n expression: \"modifiedJobForm.maxWorkerCount\"\n }\n },\n [\n _c(\"template\", { slot: \"prepend\" }, [\n _vm._v(_vm._s(_vm.$t(\"message.maxWorkerNum\")))\n ])\n ],\n 2\n )\n ],\n 1\n )\n ],\n 1\n )\n ],\n 1\n ),\n _c(\n \"el-form-item\",\n { attrs: { label: _vm.$t(\"message.alarmConfig\") } },\n [\n _c(\n \"el-select\",\n {\n attrs: {\n multiple: \"\",\n filterable: \"\",\n placeholder: _vm.$t(\"message.alarmSelectorPLH\")\n },\n model: {\n value: _vm.modifiedJobForm.notifyUserIds,\n callback: function($$v) {\n _vm.$set(_vm.modifiedJobForm, \"notifyUserIds\", $$v)\n },\n expression: \"modifiedJobForm.notifyUserIds\"\n }\n },\n _vm._l(_vm.userList, function(user) {\n return _c(\"el-option\", {\n key: user.id,\n attrs: { label: user.username, value: user.id }\n })\n }),\n 1\n )\n ],\n 1\n ),\n _c(\n \"el-form-item\",\n [\n _c(\n \"el-button\",\n { attrs: { type: \"primary\" }, on: { click: _vm.saveJob } },\n [_vm._v(_vm._s(_vm.$t(\"message.save\")))]\n ),\n _c(\n \"el-button\",\n {\n on: {\n click: function($event) {\n _vm.modifiedJobFormVisible = false\n }\n }\n },\n [_vm._v(_vm._s(_vm.$t(\"message.cancel\")))]\n )\n ],\n 1\n )\n ],\n 1\n )\n ],\n 1\n )\n ],\n 1\n )\n}\nvar staticRenderFns = []\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack:///./src/components/views/JobManager.vue?./node_modules/cache-loader/dist/cjs.js?%7B%22cacheDirectory%22:%22node_modules/.cache/vue-loader%22,%22cacheIdentifier%22:%22f7b44cbc-vue-loader-template%22%7D!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options");
+eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"render\", function() { return render; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"staticRenderFns\", function() { return staticRenderFns; });\nvar render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\n \"div\",\n { attrs: { id: \"wf_instance_manager\" } },\n [\n _c(\n \"el-row\",\n [\n _c(\n \"el-col\",\n { attrs: { span: 20 } },\n [\n _c(\n \"el-form\",\n {\n staticClass: \"el-form--inline\",\n attrs: { inline: true, model: _vm.wfInstanceQueryContent }\n },\n [\n _c(\n \"el-form-item\",\n { attrs: { label: _vm.$t(\"message.wfId\") } },\n [\n _c(\"el-input\", {\n attrs: { placeholder: _vm.$t(\"message.wfId\") },\n model: {\n value: _vm.wfInstanceQueryContent.workflowId,\n callback: function($$v) {\n _vm.$set(\n _vm.wfInstanceQueryContent,\n \"workflowId\",\n $$v\n )\n },\n expression: \"wfInstanceQueryContent.workflowId\"\n }\n })\n ],\n 1\n ),\n _c(\n \"el-form-item\",\n { attrs: { label: _vm.$t(\"message.wfInstanceId\") } },\n [\n _c(\"el-input\", {\n attrs: { placeholder: _vm.$t(\"message.wfInstanceId\") },\n model: {\n value: _vm.wfInstanceQueryContent.wfInstanceId,\n callback: function($$v) {\n _vm.$set(\n _vm.wfInstanceQueryContent,\n \"wfInstanceId\",\n $$v\n )\n },\n expression: \"wfInstanceQueryContent.wfInstanceId\"\n }\n })\n ],\n 1\n ),\n _c(\n \"el-form-item\",\n { attrs: { label: _vm.$t(\"message.status\") } },\n [\n _c(\n \"el-select\",\n {\n attrs: { placeholder: _vm.$t(\"message.status\") },\n model: {\n value: _vm.wfInstanceQueryContent.status,\n callback: function($$v) {\n _vm.$set(\n _vm.wfInstanceQueryContent,\n \"status\",\n $$v\n )\n },\n expression: \"wfInstanceQueryContent.status\"\n }\n },\n _vm._l(_vm.wfInstanceStatusOptions, function(item) {\n return _c(\"el-option\", {\n key: item.key,\n attrs: { label: item.label, value: item.key }\n })\n }),\n 1\n )\n ],\n 1\n ),\n _c(\n \"el-form-item\",\n [\n _c(\n \"el-button\",\n {\n attrs: { type: \"primary\" },\n on: { click: _vm.listWfInstances }\n },\n [_vm._v(_vm._s(_vm.$t(\"message.query\")))]\n ),\n _c(\n \"el-button\",\n {\n attrs: { type: \"cancel\" },\n on: { click: _vm.onClickRest }\n },\n [_vm._v(_vm._s(_vm.$t(\"message.reset\")))]\n )\n ],\n 1\n )\n ],\n 1\n )\n ],\n 1\n ),\n _c(\"el-col\", { attrs: { span: 4 } }, [\n _c(\n \"div\",\n { staticStyle: { float: \"right\", \"padding-right\": \"10px\" } },\n [\n _c(\n \"el-button\",\n {\n attrs: { type: \"primary\" },\n on: { click: _vm.listWfInstances }\n },\n [_vm._v(_vm._s(_vm.$t(\"message.refresh\")))]\n )\n ],\n 1\n )\n ])\n ],\n 1\n ),\n _c(\n \"el-row\",\n [\n _c(\n \"el-table\",\n {\n staticStyle: { width: \"100%\" },\n attrs: {\n data: _vm.wfInstancePageResult.data,\n \"row-class-name\": _vm.wfInstanceTableRowClassName\n }\n },\n [\n _c(\"el-table-column\", {\n attrs: {\n prop: \"workflowId\",\n label: _vm.$t(\"message.wfId\"),\n width: \"160\"\n }\n }),\n _c(\"el-table-column\", {\n attrs: { prop: \"workflowName\", label: _vm.$t(\"message.wfName\") }\n }),\n _c(\"el-table-column\", {\n attrs: {\n prop: \"wfInstanceId\",\n label: _vm.$t(\"message.wfInstanceId\")\n }\n }),\n _c(\"el-table-column\", {\n attrs: {\n prop: \"status\",\n label: _vm.$t(\"message.status\"),\n width: \"160\"\n },\n scopedSlots: _vm._u([\n {\n key: \"default\",\n fn: function(scope) {\n return [\n _vm._v(\n \" \" +\n _vm._s(_vm.fetchWFStatus(scope.row.status)) +\n \" \"\n )\n ]\n }\n }\n ])\n }),\n _c(\"el-table-column\", {\n attrs: {\n prop: \"actualTriggerTime\",\n label: _vm.$t(\"message.triggerTime\")\n }\n }),\n _c(\"el-table-column\", {\n attrs: {\n prop: \"finishedTime\",\n label: _vm.$t(\"message.finishedTime\")\n }\n }),\n _c(\"el-table-column\", {\n attrs: { label: _vm.$t(\"message.operation\"), width: \"300\" },\n scopedSlots: _vm._u([\n {\n key: \"default\",\n fn: function(scope) {\n return [\n _c(\n \"el-button\",\n {\n attrs: { size: \"medium\" },\n on: {\n click: function($event) {\n return _vm.onClickShowDetail(scope.row)\n }\n }\n },\n [_vm._v(_vm._s(_vm.$t(\"message.detail\")))]\n ),\n _c(\n \"el-button\",\n {\n attrs: { size: \"medium\" },\n on: {\n click: function($event) {\n return _vm.onClickStop(scope.row)\n }\n }\n },\n [_vm._v(_vm._s(_vm.$t(\"message.stop\")))]\n )\n ]\n }\n }\n ])\n })\n ],\n 1\n )\n ],\n 1\n ),\n _c(\n \"el-row\",\n [\n _c(\n \"el-col\",\n { attrs: { span: 24 } },\n [\n _c(\"el-pagination\", {\n attrs: {\n total: this.wfInstancePageResult.totalItems,\n \"page-size\": this.wfInstancePageResult.pageSize,\n layout: \"prev, pager, next\"\n },\n on: { \"current-change\": _vm.onClickChangeInstancePage }\n })\n ],\n 1\n )\n ],\n 1\n )\n ],\n 1\n )\n}\nvar staticRenderFns = []\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack:///./src/components/views/WFInstanceManager.vue?./node_modules/cache-loader/dist/cjs.js?%7B%22cacheDirectory%22:%22node_modules/.cache/vue-loader%22,%22cacheIdentifier%22:%22f7b44cbc-vue-loader-template%22%7D!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options");
/***/ }),
-/***/ "./src/components/views/JobManager.vue":
-/*!*********************************************!*\
- !*** ./src/components/views/JobManager.vue ***!
- \*********************************************/
+/***/ "./node_modules/css-loader/dist/cjs.js?!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src/index.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/views/WFInstanceManager.vue?vue&type=style&index=0&lang=css&":
+/*!**************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\
+ !*** ./node_modules/css-loader/dist/cjs.js??ref--6-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--6-oneOf-1-2!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/views/WFInstanceManager.vue?vue&type=style&index=0&lang=css& ***!
+ \**************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+eval("// Imports\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\nexports = ___CSS_LOADER_API_IMPORT___(false);\n// Module\nexports.push([module.i, \"\\nsvg{\\n font-size: 10px;\\n border: 1px solid red;\\n}\\ntext {\\n font-weight: 300;\\n font-family: \\\"Helvetica Neue\\\", Helvetica, Arial, sans-serif;\\n font-size: 14px;\\n}\\n.node rect {\\n stroke: #999;\\n fill: #fff;\\n stroke-width: 1.5px;\\n}\\n.edgePath path {\\n stroke: #333;\\n stroke-width: 1px;\\n}\\n\\n\", \"\"]);\n// Exports\nmodule.exports = exports;\n\n\n//# sourceURL=webpack:///./src/components/views/WFInstanceManager.vue?./node_modules/css-loader/dist/cjs.js??ref--6-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--6-oneOf-1-2!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options");
+
+/***/ }),
+
+/***/ "./node_modules/vue-style-loader/index.js?!./node_modules/css-loader/dist/cjs.js?!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src/index.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/views/WFInstanceManager.vue?vue&type=style&index=0&lang=css&":
+/*!****************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\
+ !*** ./node_modules/vue-style-loader??ref--6-oneOf-1-0!./node_modules/css-loader/dist/cjs.js??ref--6-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--6-oneOf-1-2!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/views/WFInstanceManager.vue?vue&type=style&index=0&lang=css& ***!
+ \****************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+eval("// style-loader: Adds some css to the DOM by adding a