├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── docs
├── 任务流回滚.drawio
├── 任务流回滚.jpg
├── 任务流回滚生命周期.drawio
├── 任务流回滚生命周期.jpg
├── 任务流执行.drawio
├── 任务流执行.jpg
├── 任务流执行生命周期.drawio
├── 任务流执行生命周期.jpg
├── 架构图.drawio
├── 架构图.jpg
├── 集群模式.drawio
└── 集群模式.jpg
├── pom.xml
├── wolf-flow-core
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── me
│ │ │ └── kpali
│ │ │ └── wolfflow
│ │ │ └── core
│ │ │ ├── WolfFlowCoreApplication.java
│ │ │ ├── cluster
│ │ │ ├── IClusterController.java
│ │ │ └── impl
│ │ │ │ └── DefaultClusterController.java
│ │ │ ├── config
│ │ │ ├── ClusterConfig.java
│ │ │ ├── ExecutorConfig.java
│ │ │ └── SchedulerConfig.java
│ │ │ ├── enums
│ │ │ ├── TaskFlowScheduleStatusEnum.java
│ │ │ ├── TaskFlowStatusEnum.java
│ │ │ └── TaskStatusEnum.java
│ │ │ ├── event
│ │ │ ├── ScheduleStatusChangeEvent.java
│ │ │ ├── ScheduleStatusEventPublisher.java
│ │ │ ├── TaskFlowStatusChangeEvent.java
│ │ │ ├── TaskFlowStatusEventPublisher.java
│ │ │ ├── TaskStatusChangeEvent.java
│ │ │ └── TaskStatusEventPublisher.java
│ │ │ ├── exception
│ │ │ ├── GenerateNodeIdException.java
│ │ │ ├── InvalidCronExpressionException.java
│ │ │ ├── InvalidTaskFlowException.java
│ │ │ ├── TaskExecuteException.java
│ │ │ ├── TaskFlowExecuteException.java
│ │ │ ├── TaskFlowInterruptedException.java
│ │ │ ├── TaskFlowLogException.java
│ │ │ ├── TaskFlowQueryException.java
│ │ │ ├── TaskFlowRollbackException.java
│ │ │ ├── TaskFlowStopException.java
│ │ │ ├── TaskFlowTriggerException.java
│ │ │ ├── TaskInterruptedException.java
│ │ │ ├── TaskLogException.java
│ │ │ ├── TaskRollbackException.java
│ │ │ ├── TaskStopException.java
│ │ │ └── TryLockException.java
│ │ │ ├── executor
│ │ │ ├── ITaskFlowExecutor.java
│ │ │ └── impl
│ │ │ │ └── DefaultTaskFlowExecutor.java
│ │ │ ├── launcher
│ │ │ └── Launcher.java
│ │ │ ├── logger
│ │ │ ├── ITaskFlowLogger.java
│ │ │ ├── ITaskLogger.java
│ │ │ └── impl
│ │ │ │ ├── DefaultTaskFlowLogger.java
│ │ │ │ └── DefaultTaskLogger.java
│ │ │ ├── model
│ │ │ ├── ClusterConstants.java
│ │ │ ├── DeliveryContextKey.java
│ │ │ ├── Link.java
│ │ │ ├── ManualConfirmed.java
│ │ │ ├── Task.java
│ │ │ ├── TaskContextKey.java
│ │ │ ├── TaskFlow.java
│ │ │ ├── TaskFlowContextKey.java
│ │ │ ├── TaskFlowExecRequest.java
│ │ │ ├── TaskFlowLog.java
│ │ │ ├── TaskFlowStatus.java
│ │ │ ├── TaskLog.java
│ │ │ ├── TaskLogLine.java
│ │ │ ├── TaskLogResult.java
│ │ │ └── TaskStatus.java
│ │ │ ├── monitor
│ │ │ ├── IMonitor.java
│ │ │ └── impl
│ │ │ │ └── DefaultMonitor.java
│ │ │ ├── querier
│ │ │ ├── ITaskFlowQuerier.java
│ │ │ └── impl
│ │ │ │ └── DefaultTaskFlowQuerier.java
│ │ │ ├── scheduler
│ │ │ ├── ITaskFlowScheduler.java
│ │ │ └── impl
│ │ │ │ ├── DefaultTaskFlowScheduler.java
│ │ │ │ └── quartz
│ │ │ │ ├── MyDynamicScheduler.java
│ │ │ │ ├── MyDynamicSchedulerConfig.java
│ │ │ │ ├── MyJobFactory.java
│ │ │ │ └── MyQuartzJobBean.java
│ │ │ └── util
│ │ │ ├── IdGenerator.java
│ │ │ ├── SnowFlake.java
│ │ │ ├── TaskFlowUtils.java
│ │ │ └── context
│ │ │ ├── ContextWrapper.java
│ │ │ ├── DeliveryContextWrapper.java
│ │ │ ├── ParamsWrapper.java
│ │ │ ├── TaskContextWrapper.java
│ │ │ └── TaskFlowContextWrapper.java
│ └── resources
│ │ └── quartz.properties
│ └── test
│ └── java
│ └── me
│ └── kpali
│ └── wolfflow
│ └── core
│ ├── BaseTest.java
│ ├── cluster
│ └── impl
│ │ └── DefaultClusterControllerTest.java
│ ├── listener
│ └── TaskFlowEventListener.java
│ ├── model
│ ├── AutoTask.java
│ └── ManualTask.java
│ ├── scheduler
│ └── impl
│ │ └── DefaultTaskFlowSchedulerTest.java
│ └── util
│ └── SpringContextUtil.java
├── wolf-flow-sample-cluster
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── me
│ │ │ └── kpali
│ │ │ └── wolfflow
│ │ │ └── sample
│ │ │ └── cluster
│ │ │ ├── WolfFlowSampleClusterApplication.java
│ │ │ ├── config
│ │ │ └── RedissonSpringDataConfig.java
│ │ │ ├── controller
│ │ │ ├── MetricsController.java
│ │ │ └── TriggerController.java
│ │ │ ├── listener
│ │ │ ├── ApplicationReadyEventListener.java
│ │ │ └── TaskFlowEventListener.java
│ │ │ ├── taskflow
│ │ │ ├── MyClusterController.java
│ │ │ ├── MyTask.java
│ │ │ ├── MyTaskFlowExecutor.java
│ │ │ ├── MyTaskFlowLogger.java
│ │ │ ├── MyTaskFlowQuerier.java
│ │ │ ├── MyTaskFlowScheduler.java
│ │ │ └── MyTaskLogger.java
│ │ │ └── util
│ │ │ └── SpringContextUtil.java
│ └── resources
│ │ ├── application.properties
│ │ ├── quartz.properties
│ │ └── redisson.yaml
│ └── test
│ └── java
│ └── me
│ └── kpali
│ └── wolfflow
│ └── sample
│ └── cluster
│ └── WolfFlowSampleClusterApplicationTests.java
├── wolf-flow-sample
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── me
│ │ │ └── kpali
│ │ │ └── wolfflow
│ │ │ └── sample
│ │ │ ├── WolfFlowSampleApplication.java
│ │ │ ├── controller
│ │ │ ├── MetricsController.java
│ │ │ └── TriggerController.java
│ │ │ ├── listener
│ │ │ ├── ApplicationReadyEventListener.java
│ │ │ └── TaskFlowEventListener.java
│ │ │ ├── taskflow
│ │ │ ├── MyTask.java
│ │ │ └── MyTaskFlowQuerier.java
│ │ │ └── util
│ │ │ └── SpringContextUtil.java
│ └── resources
│ │ ├── application.properties
│ │ └── quartz.properties
│ └── test
│ └── java
│ └── me
│ └── kpali
│ └── wolfflow
│ └── sample
│ └── WolfFlowSampleApplicationTests.java
└── wolf-flow-spring-boot-starter
├── pom.xml
└── src
└── main
├── java
└── me
│ └── kpali
│ └── wolfflow
│ └── autoconfigure
│ ├── WolfFlowAutoConfiguration.java
│ ├── config
│ ├── ClusterConfiguration.java
│ ├── EventPublisherConfiguration.java
│ ├── ExecutorConfiguration.java
│ ├── LauncherConfiguration.java
│ ├── LoggerConfiguration.java
│ ├── MonitorConfiguration.java
│ ├── QuerierConfiguration.java
│ ├── SchedulerConfiguration.java
│ └── UtilConfiguration.java
│ └── properties
│ ├── ClusterProperties.java
│ ├── ExecutorProperties.java
│ └── SchedulerProperties.java
└── resources
└── META-INF
└── spring.factories
/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**
5 | !**/src/test/**
6 | .flattened-pom.xml
7 |
8 | ### STS ###
9 | .apt_generated
10 | .classpath
11 | .factorypath
12 | .project
13 | .settings
14 | .springBeans
15 | .sts4-cache
16 |
17 | ### IntelliJ IDEA ###
18 | .idea
19 | *.iws
20 | *.iml
21 | *.ipr
22 |
23 | ### NetBeans ###
24 | /nbproject/private/
25 | /nbbuild/
26 | /dist/
27 | /nbdist/
28 | /.nb-gradle/
29 | build/
30 |
31 | ### VS Code ###
32 | .vscode/
33 |
34 | ### MacOS ###
35 | .DS_Store
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 |
3 | jdk:
4 | - openjdk8
5 |
6 | install:
7 | - mvn clean install -DskipTests=true -Dmaven.javadoc.skip=true -B -V
8 |
9 | script:
10 | - mvn test -B
11 |
12 | after_success:
13 | - bash <(curl -s https://codecov.io/bash)
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 kpali
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/docs/任务流回滚.drawio:
--------------------------------------------------------------------------------
1 | 7VjRbtowFP2aPDKROAR4BErbVdtUjWlt9zK5iUm8OTE1DoR9/RxyTeIkZUilpesmIZF7ru1cn3OPIbHQJM4uBF5EH3lAmOV0g8xCZ5bj2G53oL5yZFMgAw2EggYwqARm9BcBsAtoSgOyNAZKzpmkCxP0eZIQXxoYFoKvzWFzzsy7LnBIGsDMx6yJ3tBARrALp1/il4SGkb6z7Q2LTIz1YNjJMsIBX1cgNLXQRHAui6s4mxCWk6d5KeadP5LdFSZIIg+Z8PXy+nP/y8y+ev+QYiTOyZDbHVhlhVkKG7amrjUe559pzxqMrJENY5Zyo0kRPE0Ckq9rW2i8jqgkswX28+xatYHCIhkzSM8pYxPOuNjORfP53PF9hS+l4D9JJRN4917PU5nmznSZREiSVSDY6QXhMZFio4ZAFrnAOrRdH8J1qaGthYkq+nmAYWibcLdyyay6AHLbiZ6EV7F3/+0Tjq5v2febq5Xf+dVxmkTXWSWB6jwIuZARD3mC2bRExyXvXRWVYz5wvgC2fxApN2AjnEpuaqEIFZvbfP67ng7vqrmzDBYvog1EfipWO72LwvNqH+1E3TI8FT7Z037gIolFSOSf2rQptiAMS7oy62iTDqZec6oq3DVJr2s2iT2sqV/UBbNqDbAr46Ce2Lf7veZDf6H53Jr5Tu8+9xjuM0xwMise0X3OSd2H7NO6r+VEbriv2Sav333qWHtl7uud3mwZlRWvqehOm0tdl07LA220V2BQ90CDOk806KHq7ityr4/cN+Aj9yV91Mr0sOVXzGMyJ4hvT9aSX+8h5TrRWW5tMVIDFCVZmVRX4fZ76lhD2xp19XKqumJFyNfFUwxKUyFTiYQnpCYbQJjRMFGhr3QhCh/nelD1uDWCREyDYHsAtLWEeQ4cQWM0qGk8bGrstkjsPJfE+jexRePlAidP19ipaFys+NY13vkWND65xC3P3EeV2P7nJEZ9ZP7leUGNW//xeP9P6qbEDT1bVH9U4l7Nxc8osQrLt3LF00b5bhNNfwM=
--------------------------------------------------------------------------------
/docs/任务流回滚.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kpali/wolf-flow/2bac995f37f20c26c36fede6e9f65c0a013b1dd3/docs/任务流回滚.jpg
--------------------------------------------------------------------------------
/docs/任务流回滚生命周期.drawio:
--------------------------------------------------------------------------------
1 | 7Vttb6M4EP41lu4+bAXYvH2ElHSr7W2rZF8/VRRMwpbGWYdskvv1Z4MJIXhbqiYENidVKh7jgGeeZzyeMQAOntZX1J9P/yEhToCmhGsAL4GmqUix2D8u2eQSqxBMaBzmIqUUjON/sRhZSJdxiBdClotSQpI0nleFAZnNcJBWZD6lZFW9LSJJWBHM/QmuCcaBn9SlX+MwnYpZaGYpf4/jybR4smrYec+TX9wsZrKY+iFZ7YigB+CAEpLmV0/rAU648qp6Gf6md/tiFM/SJgPe6ZFyq72/+/j480vwgX6bzn98eSd+5ZefLMWErz/5i8dhQlbjYIrDZYLpBSVJ8uAHj3/9LWaSbgr1ULKchZg/QQXQXU3jFI/nfsB7VwwQTDZNnxLRHZFZKiysItZesDvj2WQk1KcwUX1SxRtimuL1jkhM8gqTJ5zSDbtF9OqKULhAnGqK9qq0n4aEbLpjO0PIfAGZyfanS62yC6HYVyjZrKkNhwxkokloOiUTMvMTr5S6pWK5Wsp7bgiZC3X+wGm6Efr0lympKhuv4/QbH36hi9b3nZ7LtfjlrLEpGjM23XyQqRft77ud5bisVQx8i2UXZEkD/Iz6kKC9Tyc4fRnLXLfP4oTixE/jX1WCH9zoqMYs4OnA8YDtAM8AtglcA3gWcEzgGLzLGgJbrSGlioNOEMwwqgQz6vxStTb5ZfSQX1p3+KX3kl+6hF8GsGxguRmbHOBY/eQX6hq/VK2u654w7qjEKeLRF4lzcOaIoXckZu9cOmatChwI9xCRz0iM2gPF9jXegBPJmncCnBzX5o2NDjvlLlVJpD9IlosU0wHTFw/xWaSP1zgY4Z9LvEhvowjTfkb82skjftU4AybApkzQu8UE+Eom3DFJP4kAT06EIk/yRxOhaQCtGd0iQj2E3iZ/PAZ/pkV68YAjQvGo1xkgdHoa2H8+DQp0v0wDq1M00OprdZ0Gh0qBchDHgZ84STyZMVnKLXciWuhNaYGUo/HCaqB7P2JLc789kKqoJ3dBkk08T5gMga0ADwHXAQ7KLlz+J1IoKr/HZdcql9gusL1M4mZpTAs4Q+CamUQFVt2nvS67EifJgCSEZmNhFEVaEHATsZjsEe/0hMaDoRvNjOkLoiU4Sg9jW9NUK7aV7TbUdk1bj2i5bSwvs02e+TL+N+3rTSuLn1WktmlaWRmhltR8zrTMigNgDbJ7iuQoYzwDx3OjTC7hBQrmIRQBEf4sK6tdsFG5q7C428gfYTtfnetP98Pb0f3o9ubGdQYfzhIzsnIjUuw2MSNLjR/Y1tzE1x+v7jMzVzDW3MXoWbb+kr+Ae8krY7w+hoCFuIRDtF7XOQcAyXYrSG1zPSnSxk0BlJVdmEvijknNcLB1Mb83bYuOqfBH9+PPg4E3Hp8lrKQhKDLaXMxgPQf9OpdxjnbTdUkMAttcT6Bk57BvicXUn/PLYEmTjUvZRo2nAF4ySXXn1lJ1VW+QHJJ4W90+mn5l4fuWFpkzY66OkcBhrlQHHvO1+V5NtqRyn5qdNOEu0Cq9rGYk3CAPlF1NMqhywlnAto/nbofO9c3nkXcWtFWRVYGVCfU6rIqIph3ayrYOdVPXNxPPRHPd2xaEPrYiKR6MwMIP0enc+N4hDq2OB4hadeNnUIqBTUsxsFulGFjfsvE0aD+rL3unUExVu5D4QqXVHc0Z1F9g0/oL7Fb9BdbrLxn2e3bqfA/1liILK1vFfL22kum1j+WUfeXap1YuapYiOWpq7eQZtb7EXmbxzdFu7GVbbcKlWebjqAmP3ljLNmvWave8M5IkPBry78Bpz85lO/sCItkKgVrNmiF0igizc2fkUdNTorBbp0SRvKbOcyUwI59XnJt4sfDaoFz7NoqeJAaTJTQOFYOxZvldbP51Qvl1MfT+Aw==
--------------------------------------------------------------------------------
/docs/任务流回滚生命周期.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kpali/wolf-flow/2bac995f37f20c26c36fede6e9f65c0a013b1dd3/docs/任务流回滚生命周期.jpg
--------------------------------------------------------------------------------
/docs/任务流执行.drawio:
--------------------------------------------------------------------------------
1 | 7Zhdb5swFIZ/DZeVgk0guUwyum7apGmZtmsXHPBmONSYfOzXz4AJONAoUxvRdZUiBb/n+Ot9zAnBwqtk/16QLP4MIeUWmoR7C7+zELInHlJfpXKoFW+uhUiwUCe1wpr9pk1PrRYspLmRKAG4ZJkpBpCmNJCGRoSAnZm2AW7OmpGI9oR1QHhf/cFCGdfqDHmtfkdZFDcz2+68jiSkSdY7yWMSwq4jYd/CKwEg66tkv6K8NK/xpe53+0j0uDBBU3lJh+93X75639b2xw8PBcHils7BvsH1KFvCC71hvVh5aBygoTJEN0HIGCJICfdbdSmgSENaTjNRrTbnE0CmRFuJP6mUB02XFBKUFMuE62hQiG3Vv2zUCyhnfXSjWsqhEAE9s7vmwBARUXkmDx1xqHNMIaFSHFQ/QTmRbGuug+gDFR3zWs/Vhbb9LxDM3hCoPG9MBHYfge9Yy2X58afWbGEtbLtHpfW89GwXM0nXGanc2KliaPq7YZyvgIOo+uLNZoOCQOm5FPCLdiKhe+9O3SOELRWS7s9j6NumO2BH156m+Ormrq1kdlOe4k4VcydXMtq7wGj8DxrtnBg9vtPTV11V0IVVxRmzqqALDnufyss/7Gj60g67c4HTzitw2hnd6flAWXG5LA0Ctaeuv+5DAU3gJq8qxEIlqP3v26C6iqpvH1lz21pMmuHU6uoRdfwUnjJVmoRMEimk9ASblghnUaqagYJAlb4sETH1xL/QgYSFYVX+ho6EWRKf46fDMxnP+4idAcLoWoSbP14DiPOMpE9HjDqI6xFfO2LsYfM2Hp3xwAPvszK2/3vG49/HA48fb4yfxHh6UqqvyFg12zdDVazzfg37fwA=
--------------------------------------------------------------------------------
/docs/任务流执行.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kpali/wolf-flow/2bac995f37f20c26c36fede6e9f65c0a013b1dd3/docs/任务流执行.jpg
--------------------------------------------------------------------------------
/docs/任务流执行生命周期.drawio:
--------------------------------------------------------------------------------
1 | 7Vttc5s4EP41mrn70Awg8fYROzjNXK/JxEmbfsoQEDYNsVwsN3Z//UkggrHUhExsDPXNZCZoJRm0+zzLalcAOHxcnWXBfPoviXAKDC1aAXgKDENHmsP+ccm6kDilYJIlUSHSKsE4+YXFzFK6TCK8ELJCRAlJaTKvC0Mym+GQ1mRBlpGn+rCYpFFNMA8mWBKMwyCVpV+TiE7FKgy7kn/EyWRa3lm33KLnMSgHi5UspkFEnjZE0AdwmBFCi6vH1RCnXHl1vYx+0/v8YBme0SYTPpixdmF8vPz88ONL+E92O51///JB/MrPIF2KBZ9fB4uHUUqexuEUR8sUZyd4hcMlxX/9LRZC16V2MrKcRZjfQAdw8DRNKB7Pg5D3PjE8MNmUPqaiOyYzKgysI9ZesJHJbHIltKcxkbym8gFxRvFqQyTWeIbJI6bZmg0RvaYm9C0Ap9ui/VSZz0BCNt0wnSVkgUDM5PmnK6WyC6HXN+jYltSGI4Yx0SQZnZIJmQWpX0kHlWK5WqoxnwiZC3V+x5SuhT6DJSV1ZeNVQm/59BNTtL5t9JyuxC/njXXZmLHlFpNss2x/2+ys5uWtcuJ7LLsgyyzEL6gPCdYH2QTT16HMdfsiTjKcBjT5Wef3zo2OJGIB3wSeD1wP+BZwbTCwgO8AzwaexbucEXB1CSl1HHSCYJZVJ5gl80s32uSX1UN+Gd3hl9lLfpkKflnAcYEzyNnkAc/pJ79Q1/ilG7Kue8K4vRKnDEdfJc7OmSOmXpKEPXPlmI06cCDcQkSxIjFrCxTPj/EOnCjeeQfAyX5t3tjosFPuUlcE+sN0uaA4GzJ9ZSQtA/0r/GOJF/QijnHWz4jfOHjEr1tHwATYlAlmt5gA38iESybpJxHgwYlQpkn+aCI0DaANq1tEkEPo59yPn2d8SHZyj2OSYb/PCSB0eBa4fz4LSnC/zgKnUyww5Fe1zIIdJUA5hpMwSL00mcyYjHLDHYgVZlNWIG1vtHAaqD6I2Yu51/5H1/SDOyDFDp5nS0bA1YCPwMADHsovBvxP5E90PmbArnWRWvHsPKOiA2eYX4zAwM7HMIns0d6WWknSdEhSkuVzYRzHRhhyE7GA7AFv9ETWvWVazYwZCJ6lOKa7sa1t6zXbqrYaerumlcNZbhvHz21TpL2s/037dtOqgmcd6W2aVlVDkDKaL5mWWXGYW5SNKTOjjPEMHC/NsrmEVycYMrRcUtzLyQsXbFbhKhzuNopbuN5X7/z6bnRxdeff+sOba/8oIaMqNSLNbRMyqrT4jk1dWPj881kdX83di5mn6U/53QenvCTGC2MIOIhLODzlgs4xoEe1T0F6m++SMl/cFD0q0wr38nvTtuiUhC+6G98Mh/54fJSoUkafyGrzPQbl3PPbYHWMdjNNRfgB23yXQMWmYdsSi2kw55fhMkvXgywIH/je/zWT1DdtLVVVzQZZIYWzNd296VcVuT/TIvdlzNMxNnjMk5rAZ5wotmkqt8tdan7ChHtAp3KyhpVyg9xn7GqSQ5UTzgGuuzdvO/LOP91cHUcEqCOnhiobmjKqynimHdaqNg2ypeVtxAuxXOc2BFGAnVgJByt08H18OCe+dXTDkOEAUatO/AgKMLBpAQZ2qwAD5c0aT3/2suaydfTE1o0ThSfUWt3NHEHVBTatusBuVV2gXHXJod+vk+ZboHc0VUjZKuTlikqu1h4WUbZ16x5at6hZcmSfGbUDJ9L6EnXZ5SdGm1GX67SJlaYZjz0mOnpjLdeWrNXu+WakSHQ05N+Os51dS3L2BUOqtwNqNVmG0CFiy84diUdND4XCbh0KReoqOs+RwJx7fnlS4tVSa4MC7fsoepD4S5XJ2FX8xZrVV7DFxwjVt8TQ/w8=
--------------------------------------------------------------------------------
/docs/任务流执行生命周期.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kpali/wolf-flow/2bac995f37f20c26c36fede6e9f65c0a013b1dd3/docs/任务流执行生命周期.jpg
--------------------------------------------------------------------------------
/docs/架构图.drawio:
--------------------------------------------------------------------------------
1 | 1Vtbd5s4EP41ekwOEqDLI8Y47e5JL5uT7eaphxrFpsXGxfjWX7+SANuA7PiKCfFxpBEI+L6ZkWYkA9MdLR8SfzJ8jAMeAWQES2B2AULQIEj8k5JVJiEsFwySMMhExkbwFP7hxZW5dBYGfJrLMlEax1EaTsrCfjwe835akvlJEi/Kp73GUVASTPwBrwme+n5Ul34Lg3SYSyFmm4YPPBwM81tTRLKGkV+cnL/JdOgH8WJLZHrAdJM4TrPSaOnySIJXxqW3o3X9YAkfp4dc8Ezm0+iZfIbRKFl8Y+nrbPz1DuKsm7kfzfI3zp82XRUQJPFsHHDZiwHMzmIYpvxp4vdl60KQLmTDdBSJGhTF1zCK3DiKE3Wt2et52HWlPB6nObvQEvX60+cvNOdJypdbovxtHng84mmyEqfkrQiZ2SW5alk5JYsNT8TKex1uUUQMmutHrhuDddcb+EQhR1CPpvtz/mRYq3n0Yjy5n+LZb/o8u7PqYHoW6HTkx7MBdYADgYdBR5RVgTLgEOBRKaeuPIcJCd1DATyaAtftiUPIJbKh0GwnCgdj0ZbGkysRY6MyMaTOjMWMOjMQ2VdihmiYYYB1AMXAI6DjAcdShHiKEMEPBR18IUJ2AF+lybMVTQ0QQmiND0yIhg/LOJ8Pvd85zlIEGQagpmzqiKZLEaOxFOWspmkS/+JbLRT9MDFu1obgvV0iDZkHWtF6xLk4a0jDGpVkUSStSHx3mOKop8gSrAnTMs/k6ArYMlpCFqK6PUCkQRZfC1jz3IFDFHoSbXkOlES0DXNsWBV9vj3qRw7X6pu5UuJ0gYPeAeoE45Zhbh+FOcKReKDOj0SUBrJ0kO7LfnqAQTnEU0P10zJeUDHaFr6dmoV13IwZTSRwHDO2nE8xT50jCs67ZMYya+NuC7jRTV9t4HgKZQwYUZPVE+woK/Tkpz7J2rpqiyL8eyZDVgX+3VSh74gToDVZbho39xEK4IrZ9NeZn6R/iiprHe9VizTx7VmnTfjKmh60jRlhka1jhh07X2M94Ng5/A5qMq6Uwb8+qBFAMjO40sTDrk73dOELpLrwBV4gPaMPOnXxS52bPSbWMtMgtIZy4cZuZhpQF8voDODw0StLx7DCj50d9TdBRMNeSpv00s21FdySCRWlM9KsK3LdayWDiV3GX5dz1LubIjd2eUs4Oh1coab9Wm5b1q3dzaEB5bvDFlv2zec5UBd47HXUlRCwbTBbJq2qMLo5yMfN8+t5qLaBjA2jZRAXN6sE0GJWQdVaQocWga+rQmHR1C3HxFgiLoRrPnaDfvwqqYfln2YYHYVBIG9wDZbom6un0NBwZFrXmp6vX6GS5bAAwyphZMppiqeWFKRlEOVjeiekKVR+opapwGqWeUraY1d/zJbqIzvuyulullhh+xZEztCdK6iIUIDTlITAq1myJryowjkd+hNZfI340pF7QAQafBzkxW4/8qfTsK9CYj9J6+ItsPkyTP+TvNwLLrPqi6oiyvJ6d5nzpiqrrcoXnoTirXmSyw5miAelTSl1frbwtzXwF7KER34aznmpcx0l+R2+xKF4kg39pJx5gRa5pyZh64OUe5zGs6TP8042PNf6rS5Hw6pLEbQMeFrrSCnMGoUzdEgzMW9Ah2BJgeRLn6tAQm+SVaaeBirqWfeWDQvBpn9VW23Xqndou0oyVF66NS18L8K6zYFPU0lowEr8LnQdiklKccBmNVQT1VxTQws9uqsrEsFv6JFWKd+dXpnl9L9NrJMVCVZ7Eoq08ZmsWUU6MoCrrRi0LbaortM0Glt8W/DBw/fv5veXH4+f3Mce+WD81G5l2hNaMMCsNuaSrdqGo0Y3Cyz//fNXvOr+ejSihLkPI2S+LI7cJaZdkn5zy0b7l6Sr4XTDC9If+6PX7mzwD/H/puTjcrX8/XmuYeZLIrse8tl0D4DvNDRGh8bG6AKxsRZvXSqZqGQbLG1bvfymSK6O3Sn+Cvq7Vxkv4fztsiXgoovSlki7Tgw02JWI0a+xiIGTKh/jGKqw9jHFeKDxVflGiaJpOvHHReMo7Cvr4sldwgehwHh1N9myt+wK8fzbF+k62tp/seOalvk+ZJc3sGG77vmEjjXo+XQTqjrhTH5nhWyT+W7CH9fktnd3jF3Yzz4akGYH+dVo0OTMmwiQ1uFPFhzZR8ZGO6loSRi0/llTwXMxEh6d4rHe6OjkuEdUN7+Zyk7f/PLM9P4H
--------------------------------------------------------------------------------
/docs/架构图.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kpali/wolf-flow/2bac995f37f20c26c36fede6e9f65c0a013b1dd3/docs/架构图.jpg
--------------------------------------------------------------------------------
/docs/集群模式.drawio:
--------------------------------------------------------------------------------
1 | 7VtNc6M4EP01OiaFAPFxBNvsHmarZmsOs3vaIkax2cGWg+XE3l+/EiBAEjg4NiQzFSflQi0QSP3oft0tA2u2Of6Wx7v1HyTBGTCN5AisOTBNaJsm4P9GciolnhCs8jQpRUYj+Jb+h6srhfSQJnhfyUoRJSSj6U4WLsl2i5dUksV5Tl7k0x5JlkiCXbzCmuDbMs506fc0oetKCh2/6fgdp6s1FfNzy45NLE6uZrJfxwl5aYmsBbBmOSG0PNocZzjjiyevS9TTWz9Yjrd0yAXPm+PX7GQSY2c8/bmc7777T/s7WE3jOc4O1Yyrp6UnsQQ5OWwTzEcxgBW+rFOKv+3iJe99YUpnsjXdZKwF2eFjmmUzkpG8uNZ6LD5cTra00i60WXtPc/IDt840ig/rqR4I5xQfe6cK6wVkyMNkg2l+YqeIC4QSBOhQ2XxpNOj5lWzdUh7yBHIq1KzqoZuFZQfV2l6wzpbRsc5Oxu4bPrCDFS0mXgr4UkkacJ4ORHTc7YtFDNgJ0Nkdm856lIUP/BB4Dli4IFyAwBbjsgcvh5Zvx8StR7hK94qOuQ5T9ioFWbraMuEDoZRsdJDg4tMFCsuxfCu5ESgcUwKF5Xs6KkxHRwU7dSRUQGc6VCDgeQUqEAjZgVUczIAXFV3z4sADoVF0OcCfcSHvCkAAp4NQDzJUKFGyO4sXFYo3wQ+U8APFEG38iPe8jR8IvZHwI4z1OeuNE+bPqibJ6ZqsyDbOFo00lBXUnPOF8EUu1PIvpvRUrWd8oERWGlvA/PQXv/4eiebf7b75sRq8bJ2q1vKQPxf37TIemm4dJ4pCq+4R3tistctnel63bGHIIV/iM0taOQ4a5ytMzxn0HrDkOItp+iw/SJfiq0u/krR4ryuQma5ipGxTHqJ8sOoqBT71Y1zhpwbwgdcRJSn2DYDqIAduFEWduldx0wKjeREa3wFEpv9LgsiGGojMe9Yu3EkEfMg5isc8DeSexvNB4HLfw9yMNysOIhC6vCtkEh1/zIRTGS85Zv4vfihO4Krc8ZkVc0UhQHMmiSu/sWS6xHmHQ9mkSVJgN4sfcBbGyx+rwi4O4bK83QXWXqdTBSvVEzchQhtrZ17PXhd1xzDv2Jak/Dvhfd4KKnEKeXzc41Hw4uo2h5OTAPg2J7HsO/A4LhgVYXBgEvYd+lADRqF2nC+ecan9wpSIqIvjIon369rR9dqbLdlinYogg/8JgHwl+5SmpBNSX5QTatrbTWLIgWbplt1dBLBGF17ZPHZ8mpvjigfa90wb6RLf7zGztPn+Pt7tMjY0v+M/pYwPst+VIz6mRzwSK2L990gCXB3yt3gRNGAHLzLNfhBexYu8NwFKtzSfgJoeUMhyFTi57w0nuytMe39SFEVVxuQiUuReRIoU11bf8oZkyR/KuM1RyJJvyP7SEtqeiizp3s/pI0uIf7PInFGjYA4C8xcgSwqibkmWSkWeJ0uGIylf3PPjcqWO+GyAa7M+XdsHcG0eMjWu5Ax1bmPlIE37Fs7tM4f0Fo82Ug5JMFkBMjX8LyegeTRtIBsZsnVEyrOM7BrNLmM3IGHAKyAe8KMq6e27GqAbuMKLc9Kz2QIV4f0IFsKCMhmBjl65EtNpmwdVw7erW+mpHN27FB4oKgoHHldEWBwEC15N4F1zIIptN1NBFM1mY8Uf/gdTQUeSfwgTHPctiCKffcZRgeugD6aCIT5ymwR8vwEnIlm836fLoTltjSHLK71M8IP3oLq6axzYq47J7VZPa/lRR51LyK50X0g2gbanMJ+h3gsasvey3WkDOwtpoIFlYGeDMOT/dXWVv7PFG83fYhcEThP8/Wzx3JjJb/us1WDxnOMJY/lWDNZJcwV04wV0dtfOkPdPLl1ScTumtJ1bYs2aubPjhrjzxgjVNnMo30Yj8W2RdhGGRoDwUotl2XLq04TupBZL+M8WFK3SYjHSvQABKjaGMOvlfNbtLjNdttGNvMZ0oXqXSKV8hG7iTe+giimRgpjAtFkj0KY6YfjxaFNPcXYa2gQhVImTsu1oMHHSa3qWP23kb+uEG9VJcSXw6WdTP5sBGjMXbo3PnXoszh20JzM4HYXfy7nU1LW5mj6Zw+mTZNT6cqdNtvTdinsCU69zM3MUbuarRtFSgsChRtGzZfc8OTfTc6FuHzf7LBNeZBq910zjzcuEYmiRVxKW0lQwNZ6lRDeJOj+rPvqmo/eq+iBPNlC2Cqahlg55SsQwMfdD3dsB1b0QA4oQP5uRq3F6eyOHzgegjP7ZSKb8t0mkiZ/xTWDR9EqVXTtIJVVxTcjw6v6HSjQcOF2FF9my1nsxuszdxVmM4YUYW3FQtlu9VNJ2hY4f0plGP1CuqsQgPUXljREYfnQtv86HhmvZ0Qol42mZNZtfvJavfvO7YWvxPw==
--------------------------------------------------------------------------------
/docs/集群模式.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kpali/wolf-flow/2bac995f37f20c26c36fede6e9f65c0a013b1dd3/docs/集群模式.jpg
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 2.2.4.RELEASE
9 |
10 |
11 | me.kpali
12 | wolf-flow
13 | 2.1.1
14 | pom
15 | wolf-flow ${project.version}
16 | Wolf flow is a simple, lightweight job scheduling engine
17 |
18 |
19 | 1.8
20 | ${java.version}
21 | ${java.version}
22 | UTF-8
23 |
24 | 3.6.1
25 | 0.8.6
26 | 2.22.2
27 | 1.6
28 |
29 |
30 |
31 | wolf-flow-core
32 | wolf-flow-spring-boot-starter
33 |
34 |
35 |
36 |
37 | The MIT License (MIT)
38 | https://www.mit-license.org/
39 |
40 |
41 |
42 |
43 | kpali
44 | kpali@qq.com
45 |
46 |
47 |
48 | https://github.com/kpali/wolf-flow
49 | https://github.com/kpali/wolf-flow.git
50 | https://github.com/kpali/wolf-flow.git
51 |
52 |
53 |
54 | release
55 |
56 |
57 |
58 |
59 | org.apache.maven.plugins
60 | maven-source-plugin
61 |
62 |
63 | package
64 |
65 | jar-no-fork
66 |
67 |
68 |
69 |
70 |
71 |
72 | org.apache.maven.plugins
73 | maven-javadoc-plugin
74 |
75 |
76 | package
77 |
78 | jar
79 |
80 |
81 |
82 |
83 |
84 |
85 | org.apache.maven.plugins
86 | maven-gpg-plugin
87 | ${maven-gpg-plugin.version}
88 |
89 |
90 | verify
91 |
92 | sign
93 |
94 |
95 |
96 |
97 |
98 |
99 | maven-compiler-plugin
100 | ${maven-compiler-plugin.version}
101 |
102 | true
103 | ${maven.compiler.source}
104 | ${maven.compiler.target}
105 | ${project.build.sourceEncoding}
106 |
107 |
108 |
109 |
110 |
111 |
112 | sonatype-nexus-snapshots
113 | https://oss.sonatype.org/content/repositories/snapshots/
114 |
115 |
116 | sonatype-nexus-staging
117 | https://oss.sonatype.org/service/local/staging/deploy/maven2/
118 |
119 |
120 |
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/wolf-flow-core/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | me.kpali
7 | wolf-flow
8 | 2.1.1
9 |
10 | wolf-flow-core
11 | wolf-flow-core ${project.version}
12 |
13 |
14 | 2.10.2
15 | 2.3.0
16 | 20.0
17 | 1.6.0
18 |
19 |
20 |
21 |
22 | org.springframework.boot
23 | spring-boot-starter
24 | provided
25 |
26 |
27 |
28 |
29 | org.springframework
30 | spring-context-support
31 |
32 |
33 | org.springframework
34 | spring-jdbc
35 |
36 |
37 | org.quartz-scheduler
38 | quartz
39 | ${quartz.version}
40 |
41 |
42 |
43 | com.fasterxml.jackson.core
44 | jackson-databind
45 | ${jackson.version}
46 |
47 |
48 |
49 | com.google.guava
50 | guava
51 | ${guava.version}
52 |
53 |
54 |
55 |
56 | io.micrometer
57 | micrometer-registry-prometheus
58 | ${micrometer.version}
59 |
60 |
61 |
62 |
63 | org.springframework.boot
64 | spring-boot-starter-test
65 | test
66 |
67 |
68 | org.junit.vintage
69 | junit-vintage-engine
70 |
71 |
72 |
73 |
74 | org.jacoco
75 | jacoco-maven-plugin
76 | ${maven-jacoco-plugin.version}
77 | maven-plugin
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 | maven-compiler-plugin
86 | ${maven-compiler-plugin.version}
87 |
88 | true
89 | ${maven.compiler.source}
90 | ${maven.compiler.target}
91 | ${project.build.sourceEncoding}
92 |
93 |
94 |
95 |
96 | org.jacoco
97 | jacoco-maven-plugin
98 | ${maven-jacoco-plugin.version}
99 |
100 |
101 |
102 | prepare-agent
103 |
104 |
105 | jacocoArgLine
106 |
107 |
108 |
109 | report
110 | test
111 |
112 | report
113 |
114 |
115 |
116 |
117 |
118 |
119 | maven-surefire-plugin
120 | ${maven-surefire-plugin.version}
121 |
122 |
123 | ${jacocoArgLine}
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/WolfFlowCoreApplication.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class WolfFlowCoreApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(WolfFlowCoreApplication.class, args);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/cluster/IClusterController.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.cluster;
2 |
3 | import me.kpali.wolfflow.core.exception.GenerateNodeIdException;
4 | import me.kpali.wolfflow.core.model.ManualConfirmed;
5 | import me.kpali.wolfflow.core.model.TaskFlowExecRequest;
6 |
7 | import java.util.concurrent.TimeUnit;
8 |
9 | /**
10 | * 集群控制器
11 | *
12 | * @author kpali
13 | */
14 | public interface IClusterController {
15 | /**
16 | * 启动集群控制器
17 | */
18 | void startup();
19 |
20 | /**
21 | * 生成节点ID
22 | */
23 | void generateNodeId() throws GenerateNodeIdException;
24 |
25 | /**
26 | * 获取当前节点ID
27 | *
28 | * @return 节点ID
29 | */
30 | Long getNodeId();
31 |
32 | /**
33 | * 发送当前节点心跳
34 | */
35 | void heartbeat();
36 |
37 | /**
38 | * 查询其他节点是否存活
39 | *
40 | * @param nodeId
41 | * @return
42 | */
43 | boolean isNodeAlive(Long nodeId);
44 |
45 | /**
46 | * 加锁,如果暂时无法加锁,则当前线程休眠,直到加锁成功
47 | * 加锁成功后,解锁需要调用unlock方法
48 | *
49 | * @param name
50 | */
51 | void lock(String name);
52 |
53 | /**
54 | * 加锁,如果暂时无法加锁,则当前线程休眠,直到加锁成功
55 | * 加锁成功后,解锁需要调用unlock方法或在到达指定时间后自动解锁
56 | *
57 | * @param name 锁名称
58 | * @param leaseTime 租赁时间,即上锁后多久自动解锁
59 | * @param unit 时间单位
60 | */
61 | void lock(String name, long leaseTime, TimeUnit unit);
62 |
63 | /**
64 | * 尝试加锁
65 | *
66 | * @param name 锁名称
67 | * @param waitTime 等待时间,即尝试加锁的最多等待时间
68 | * @param leaseTime 租赁时间,即上锁后多久自动解锁
69 | * @param unit 时间单位
70 | * @return 成功则返回true
71 | */
72 | boolean tryLock(String name, long waitTime, long leaseTime, TimeUnit unit);
73 |
74 | /**
75 | * 解锁
76 | *
77 | * @param name 锁名称
78 | */
79 | void unlock(String name);
80 |
81 | /**
82 | * 插入任务流执行请求到队列中
83 | *
84 | * @param request
85 | * @return 成功返回true
86 | */
87 | boolean execRequestOffer(TaskFlowExecRequest request);
88 |
89 | /**
90 | * 移除并返回任务流执行队列的首个元素
91 | *
92 | * @return 若队列为空则返回null
93 | */
94 | TaskFlowExecRequest execRequestPoll();
95 |
96 | /**
97 | * 新增任务流停止请求
98 | *
99 | * @param taskFlowLogId
100 | */
101 | void stopRequestAdd(Long taskFlowLogId);
102 |
103 | /**
104 | * 查询是否包含任务流停止请求
105 | *
106 | * @param taskFlowLogId
107 | * @return
108 | */
109 | Boolean stopRequestContains(Long taskFlowLogId);
110 |
111 | /**
112 | * 删除任务流停止请求
113 | *
114 | * @param taskFlowLogId
115 | */
116 | void stopRequestRemove(Long taskFlowLogId);
117 |
118 | /**
119 | * 新增手工确认信息
120 | *
121 | * @param manualConfirmed
122 | */
123 | void manualConfirmedAdd(ManualConfirmed manualConfirmed);
124 |
125 | /**
126 | * 获取手工确认信息
127 | *
128 | * @param taskLogId
129 | * @return
130 | */
131 | ManualConfirmed manualConfirmedGet(Long taskLogId);
132 |
133 | /**
134 | * 删除手工确认信息
135 | *
136 | * @param taskLogId
137 | */
138 | void manualConfirmedRemove(Long taskLogId);
139 | }
140 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/config/ClusterConfig.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.config;
2 |
3 | import org.springframework.stereotype.Component;
4 |
5 | /**
6 | * 集群控制器配置
7 | *
8 | * @author kpali
9 | */
10 | @Component
11 | public class ClusterConfig {
12 | /**
13 | * 节点发送心跳间隔时间,单位秒
14 | */
15 | private Integer nodeHeartbeatInterval;
16 | /**
17 | * 节点心跳有效期,单位秒
18 | */
19 | private Integer nodeHeartbeatDuration;
20 | /**
21 | * 生成节点ID获取锁后自动解锁时间,单位秒
22 | */
23 | private Integer generateNodeIdLockLeaseTime;
24 | /**
25 | * 任务流日志记录获取锁最大等待时间,单位秒
26 | */
27 | private Integer taskFlowLogLockWaitTime;
28 | /**
29 | * 任务流日志记录获取锁后自动解锁时间,单位秒
30 | */
31 | private Integer taskFlowLogLockLeaseTime;
32 | /**
33 | * 任务日志记录获取锁最大等待时间,单位秒
34 | */
35 | private Integer taskLogLockWaitTime;
36 | /**
37 | * 任务日志记录获取锁后自动解锁时间,单位秒
38 | */
39 | private Integer taskLogLockLeaseTime;
40 |
41 | public Integer getNodeHeartbeatInterval() {
42 | return nodeHeartbeatInterval;
43 | }
44 |
45 | public void setNodeHeartbeatInterval(Integer nodeHeartbeatInterval) {
46 | this.nodeHeartbeatInterval = nodeHeartbeatInterval;
47 | }
48 |
49 | public Integer getNodeHeartbeatDuration() {
50 | return nodeHeartbeatDuration;
51 | }
52 |
53 | public void setNodeHeartbeatDuration(Integer nodeHeartbeatDuration) {
54 | this.nodeHeartbeatDuration = nodeHeartbeatDuration;
55 | }
56 |
57 | public Integer getGenerateNodeIdLockLeaseTime() {
58 | return generateNodeIdLockLeaseTime;
59 | }
60 |
61 | public void setGenerateNodeIdLockLeaseTime(Integer generateNodeIdLockLeaseTime) {
62 | this.generateNodeIdLockLeaseTime = generateNodeIdLockLeaseTime;
63 | }
64 |
65 | public Integer getTaskFlowLogLockWaitTime() {
66 | return taskFlowLogLockWaitTime;
67 | }
68 |
69 | public void setTaskFlowLogLockWaitTime(Integer taskFlowLogLockWaitTime) {
70 | this.taskFlowLogLockWaitTime = taskFlowLogLockWaitTime;
71 | }
72 |
73 | public Integer getTaskFlowLogLockLeaseTime() {
74 | return taskFlowLogLockLeaseTime;
75 | }
76 |
77 | public void setTaskFlowLogLockLeaseTime(Integer taskFlowLogLockLeaseTime) {
78 | this.taskFlowLogLockLeaseTime = taskFlowLogLockLeaseTime;
79 | }
80 |
81 | public Integer getTaskLogLockWaitTime() {
82 | return taskLogLockWaitTime;
83 | }
84 |
85 | public void setTaskLogLockWaitTime(Integer taskLogLockWaitTime) {
86 | this.taskLogLockWaitTime = taskLogLockWaitTime;
87 | }
88 |
89 | public Integer getTaskLogLockLeaseTime() {
90 | return taskLogLockLeaseTime;
91 | }
92 |
93 | public void setTaskLogLockLeaseTime(Integer taskLogLockLeaseTime) {
94 | this.taskLogLockLeaseTime = taskLogLockLeaseTime;
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/config/ExecutorConfig.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.config;
2 |
3 | import org.springframework.stereotype.Component;
4 |
5 | /**
6 | * 任务流执行器配置
7 | *
8 | * @author kpali
9 | */
10 | @Component
11 | public class ExecutorConfig {
12 | /**
13 | * 任务流执行器线程池核心线程数
14 | */
15 | private Integer corePoolSize;
16 | /**
17 | * 任务流执行器线程池最大线程数
18 | */
19 | private Integer maximumPoolSize;
20 |
21 | public Integer getCorePoolSize() {
22 | return corePoolSize;
23 | }
24 |
25 | public void setCorePoolSize(Integer corePoolSize) {
26 | this.corePoolSize = corePoolSize;
27 | }
28 |
29 | public Integer getMaximumPoolSize() {
30 | return maximumPoolSize;
31 | }
32 |
33 | public void setMaximumPoolSize(Integer maximumPoolSize) {
34 | this.maximumPoolSize = maximumPoolSize;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/config/SchedulerConfig.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.config;
2 |
3 | import org.springframework.stereotype.Component;
4 |
5 | /**
6 | * 任务流调度器配置
7 | *
8 | * @author kpali
9 | */
10 | @Component
11 | public class SchedulerConfig {
12 | /**
13 | * 任务流执行请求扫描间隔,单位秒
14 | */
15 | private Integer execRequestScanInterval;
16 | /**
17 | * 定时任务流扫描间隔,单位秒
18 | */
19 | private Integer cronScanInterval;
20 | /**
21 | * 定时任务流扫描尝试获取锁最大等待时间,单位秒
22 | */
23 | private Integer cronScanLockWaitTime;
24 | /**
25 | * 定时任务流扫描获取锁后自动解锁时间,单位秒
26 | */
27 | private Integer cronScanLockLeaseTime;
28 | /**
29 | * 任务流调度器线程池核心线程数
30 | */
31 | private Integer corePoolSize;
32 | /**
33 | * 任务流调度器线程池最大线程数
34 | */
35 | private Integer maximumPoolSize;
36 |
37 | public Integer getExecRequestScanInterval() {
38 | return execRequestScanInterval;
39 | }
40 |
41 | public void setExecRequestScanInterval(Integer execRequestScanInterval) {
42 | this.execRequestScanInterval = execRequestScanInterval;
43 | }
44 |
45 | public Integer getCronScanInterval() {
46 | return cronScanInterval;
47 | }
48 |
49 | public void setCronScanInterval(Integer cronScanInterval) {
50 | this.cronScanInterval = cronScanInterval;
51 | }
52 |
53 | public Integer getCronScanLockWaitTime() {
54 | return cronScanLockWaitTime;
55 | }
56 |
57 | public void setCronScanLockWaitTime(Integer cronScanLockWaitTime) {
58 | this.cronScanLockWaitTime = cronScanLockWaitTime;
59 | }
60 |
61 | public Integer getCronScanLockLeaseTime() {
62 | return cronScanLockLeaseTime;
63 | }
64 |
65 | public void setCronScanLockLeaseTime(Integer cronScanLockLeaseTime) {
66 | this.cronScanLockLeaseTime = cronScanLockLeaseTime;
67 | }
68 |
69 | public Integer getCorePoolSize() {
70 | return corePoolSize;
71 | }
72 |
73 | public void setCorePoolSize(Integer corePoolSize) {
74 | this.corePoolSize = corePoolSize;
75 | }
76 |
77 | public Integer getMaximumPoolSize() {
78 | return maximumPoolSize;
79 | }
80 |
81 | public void setMaximumPoolSize(Integer maximumPoolSize) {
82 | this.maximumPoolSize = maximumPoolSize;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/enums/TaskFlowScheduleStatusEnum.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.enums;
2 |
3 | /**
4 | * 任务流调度状态枚举
5 | *
6 | * @author kpali
7 | */
8 | public enum TaskFlowScheduleStatusEnum {
9 |
10 | JOIN("JOIN", "Join"),
11 | UPDATE("UPDATE", "Update"),
12 | FAIL("FAIL", "Fail");
13 |
14 | private String code;
15 | private String name;
16 |
17 | TaskFlowScheduleStatusEnum(String code, String name) {
18 | this.code = code;
19 | this.name = name;
20 | }
21 |
22 | public String getCode() {
23 | return code;
24 | }
25 |
26 | public String getName() {
27 | return name;
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/enums/TaskFlowStatusEnum.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.enums;
2 |
3 | /**
4 | * 任务流状态枚举
5 | *
6 | * @author kpali
7 | */
8 | public enum TaskFlowStatusEnum {
9 |
10 | WAIT_FOR_EXECUTE("WAIT_FOR_EXECUTE", "Wait for execute"),
11 | EXECUTING("EXECUTING", "Executing"),
12 | EXECUTE_SUCCESS("EXECUTE_SUCCESS", "Execute success"),
13 | EXECUTE_FAILURE("EXECUTE_FAILURE", "Execute failure"),
14 |
15 | STOPPING("STOPPING", "Stopping"),
16 |
17 | WAIT_FOR_ROLLBACK("WAIT_FOR_ROLLBACK", "Wait for rollback"),
18 | ROLLING_BACK("ROLLING_BACK", "Rolling back"),
19 | ROLLBACK_SUCCESS("ROLLBACK_SUCCESS", "Rollback success"),
20 | ROLLBACK_FAILURE("ROLLBACK_FAILURE", "Rollback failure");
21 |
22 | private String code;
23 | private String name;
24 |
25 | TaskFlowStatusEnum(String code, String name) {
26 | this.code = code;
27 | this.name = name;
28 | }
29 |
30 | public String getCode() {
31 | return code;
32 | }
33 |
34 | public String getName() {
35 | return name;
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/enums/TaskStatusEnum.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.enums;
2 |
3 | /**
4 | * 任务状态枚举
5 | *
6 | * @author kpali
7 | */
8 | public enum TaskStatusEnum {
9 |
10 | WAIT_FOR_EXECUTE("WAIT_FOR_EXECUTE", "Wait for execute"),
11 | EXECUTING("EXECUTING", "Executing"),
12 | EXECUTE_SUCCESS("EXECUTE_SUCCESS", "Execute success"),
13 | EXECUTE_FAILURE("EXECUTE_FAILURE", "Execute failure"),
14 |
15 | STOPPING("STOPPING", "Stopping"),
16 | SKIPPED("SKIPPED", "Skipped"),
17 | MANUAL_CONFIRM("MANUAL_CONFIRM", "Manual Confirm"),
18 |
19 | WAIT_FOR_ROLLBACK("WAIT_FOR_ROLLBACK", "Wait for rollback"),
20 | ROLLING_BACK("ROLLING_BACK", "Rolling back"),
21 | ROLLBACK_SUCCESS("ROLLBACK_SUCCESS", "Rollback success"),
22 | ROLLBACK_FAILURE("ROLLBACK_FAILURE", "Rollback failure");
23 |
24 | private String code;
25 | private String name;
26 |
27 | TaskStatusEnum(String code, String name) {
28 | this.code = code;
29 | this.name = name;
30 | }
31 |
32 | public String getCode() {
33 | return code;
34 | }
35 |
36 | public String getName() {
37 | return name;
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/event/ScheduleStatusChangeEvent.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.event;
2 |
3 | import org.springframework.context.ApplicationEvent;
4 |
5 | /**
6 | * 任务流调度状态变更事件
7 | *
8 | * @author kpali
9 | */
10 | public class ScheduleStatusChangeEvent extends ApplicationEvent {
11 | public ScheduleStatusChangeEvent(Object source, Long taskFlowId, String cronExpression, String scheduleStatus) {
12 | super(source);
13 | this.taskFlowId = taskFlowId;
14 | this.cronExpression = cronExpression;
15 | this.scheduleStatus = scheduleStatus;
16 | }
17 |
18 | private Long taskFlowId;
19 | private String cronExpression;
20 | private String scheduleStatus;
21 |
22 | public Long getTaskFlowId() {
23 | return taskFlowId;
24 | }
25 |
26 | public String getCronExpression() {
27 | return cronExpression;
28 | }
29 |
30 | public String getScheduleStatus() {
31 | return scheduleStatus;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/event/ScheduleStatusEventPublisher.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.event;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.context.ApplicationEventPublisher;
5 | import org.springframework.stereotype.Component;
6 |
7 | /**
8 | * 任务流调度状态事件发布器
9 | *
10 | * @author kpali
11 | */
12 | @Component
13 | public class ScheduleStatusEventPublisher {
14 | @Autowired
15 | private ApplicationEventPublisher eventPublisher;
16 |
17 | public void publishEvent(ScheduleStatusChangeEvent scheduleStatusChangeEvent) {
18 | this.eventPublisher.publishEvent(scheduleStatusChangeEvent);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/event/TaskFlowStatusChangeEvent.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.event;
2 |
3 | import me.kpali.wolfflow.core.model.TaskFlowStatus;
4 | import org.springframework.context.ApplicationEvent;
5 |
6 | /**
7 | * 任务流状态变更事件
8 | *
9 | * @author kpali
10 | */
11 | public class TaskFlowStatusChangeEvent extends ApplicationEvent {
12 | public TaskFlowStatusChangeEvent(Object source, TaskFlowStatus taskFlowStatus) {
13 | super(source);
14 | this.taskFlowStatus = taskFlowStatus;
15 | }
16 |
17 | private TaskFlowStatus taskFlowStatus;
18 |
19 | public TaskFlowStatus getTaskFlowStatus() {
20 | return taskFlowStatus;
21 | }
22 |
23 | public void setTaskFlowStatus(TaskFlowStatus taskFlowStatus) {
24 | this.taskFlowStatus = taskFlowStatus;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/event/TaskFlowStatusEventPublisher.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.event;
2 |
3 | import me.kpali.wolfflow.core.cluster.IClusterController;
4 | import me.kpali.wolfflow.core.config.ClusterConfig;
5 | import me.kpali.wolfflow.core.exception.TaskFlowLogException;
6 | import me.kpali.wolfflow.core.exception.TryLockException;
7 | import me.kpali.wolfflow.core.logger.ITaskFlowLogger;
8 | import me.kpali.wolfflow.core.model.*;
9 | import me.kpali.wolfflow.core.util.context.TaskFlowContextWrapper;
10 | import org.springframework.beans.factory.annotation.Autowired;
11 | import org.springframework.context.ApplicationEventPublisher;
12 | import org.springframework.stereotype.Component;
13 |
14 | import java.util.Date;
15 | import java.util.concurrent.ConcurrentHashMap;
16 | import java.util.concurrent.TimeUnit;
17 |
18 | /**
19 | * 任务流状态事件发布器
20 | *
21 | * @author kpali
22 | */
23 | @Component
24 | public class TaskFlowStatusEventPublisher {
25 | @Autowired
26 | private ApplicationEventPublisher eventPublisher;
27 |
28 | @Autowired
29 | private ClusterConfig clusterConfig;
30 |
31 | @Autowired
32 | private IClusterController clusterController;
33 |
34 | @Autowired
35 | private ITaskFlowLogger taskFlowLogger;
36 |
37 | /**
38 | * 发布任务流状态变更事件
39 | *
40 | * @param taskFlow
41 | * @param context
42 | * @param status
43 | * @param message
44 | * @param record
45 | */
46 | public void publishEvent(TaskFlow taskFlow, ConcurrentHashMap context, String status, String message, boolean record) throws TryLockException, TaskFlowLogException {
47 | TaskFlowContextWrapper taskFlowContextWrapper = new TaskFlowContextWrapper(context);
48 |
49 | TaskFlowStatus taskFlowStatus = new TaskFlowStatus();
50 | taskFlowStatus.setTaskFlow(taskFlow);
51 | taskFlowStatus.setContext(taskFlowContextWrapper.getTaskFlowContext());
52 | taskFlowStatus.setStatus(status);
53 | taskFlowStatus.setMessage(message);
54 | if (record) {
55 | String taskFlowLogLock = ClusterConstants.getTaskFlowLogLock(taskFlow.getId());
56 | boolean locked = false;
57 | try {
58 | locked = this.clusterController.tryLock(
59 | taskFlowLogLock,
60 | clusterConfig.getTaskFlowLogLockWaitTime(),
61 | clusterConfig.getTaskFlowLogLockLeaseTime(),
62 | TimeUnit.SECONDS);
63 | if (!locked) {
64 | throw new TryLockException("Acquire the task flow log lock failed!");
65 | }
66 | Long taskFlowLogId = taskFlowContextWrapper.getValue(TaskFlowContextKey.LOG_ID, Long.class);
67 | boolean isRollback = taskFlowContextWrapper.getValue(TaskFlowContextKey.IS_ROLLBACK, Boolean.class);
68 | TaskFlowLog taskFlowLog = this.taskFlowLogger.get(taskFlowLogId);
69 | boolean isNewLog = false;
70 | Date now = new Date();
71 | if (taskFlowLog == null) {
72 | isNewLog = true;
73 | taskFlowLog = new TaskFlowLog();
74 | taskFlowLog.setCreationTime(now);
75 | }
76 | taskFlowLog.setLogId(taskFlowLogId);
77 | taskFlowLog.setTaskFlowId(taskFlow.getId());
78 | taskFlowLog.setTaskFlow(taskFlow);
79 | taskFlowLog.setContext(taskFlowContextWrapper.getTaskFlowContext());
80 | taskFlowLog.setStatus(status);
81 | taskFlowLog.setMessage(message);
82 | taskFlowLog.setRollback(isRollback);
83 | taskFlowLog.setUpdateTime(now);
84 | if (isNewLog) {
85 | this.taskFlowLogger.add(taskFlowLog);
86 | } else {
87 | this.taskFlowLogger.update(taskFlowLog);
88 | }
89 | } finally {
90 | if (locked) {
91 | this.clusterController.unlock(taskFlowLogLock);
92 | }
93 | }
94 | }
95 | TaskFlowStatusChangeEvent taskFlowStatusChangeEvent = new TaskFlowStatusChangeEvent(this, taskFlowStatus);
96 | this.eventPublisher.publishEvent(taskFlowStatusChangeEvent);
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/event/TaskStatusChangeEvent.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.event;
2 |
3 | import me.kpali.wolfflow.core.model.TaskStatus;
4 | import org.springframework.context.ApplicationEvent;
5 |
6 | /**
7 | * 任务状态变更事件
8 | *
9 | * @author kpali
10 | */
11 | public class TaskStatusChangeEvent extends ApplicationEvent {
12 | public TaskStatusChangeEvent(Object source, TaskStatus taskStatus) {
13 | super(source);
14 | this.taskStatus = taskStatus;
15 | }
16 |
17 | private TaskStatus taskStatus;
18 |
19 | public TaskStatus getTaskStatus() {
20 | return taskStatus;
21 | }
22 |
23 | public void setTaskStatus(TaskStatus taskStatus) {
24 | this.taskStatus = taskStatus;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/event/TaskStatusEventPublisher.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.event;
2 |
3 | import me.kpali.wolfflow.core.cluster.IClusterController;
4 | import me.kpali.wolfflow.core.config.ClusterConfig;
5 | import me.kpali.wolfflow.core.exception.TaskLogException;
6 | import me.kpali.wolfflow.core.exception.TryLockException;
7 | import me.kpali.wolfflow.core.logger.ITaskLogger;
8 | import me.kpali.wolfflow.core.model.*;
9 | import me.kpali.wolfflow.core.util.context.TaskContextWrapper;
10 | import me.kpali.wolfflow.core.util.context.TaskFlowContextWrapper;
11 | import org.springframework.beans.factory.annotation.Autowired;
12 | import org.springframework.context.ApplicationEventPublisher;
13 | import org.springframework.stereotype.Component;
14 |
15 | import java.util.Date;
16 | import java.util.concurrent.ConcurrentHashMap;
17 | import java.util.concurrent.TimeUnit;
18 |
19 | /**
20 | * 任务状态事件发布器
21 | *
22 | * @author kpali
23 | */
24 | @Component
25 | public class TaskStatusEventPublisher {
26 | @Autowired
27 | private ApplicationEventPublisher eventPublisher;
28 |
29 | @Autowired
30 | private ClusterConfig clusterConfig;
31 |
32 | @Autowired
33 | private IClusterController clusterController;
34 |
35 | @Autowired
36 | private ITaskLogger taskLogger;
37 |
38 | /**
39 | * 发布任务状态变更事件
40 | *
41 | * @param task
42 | * @param taskFlowId
43 | * @param context
44 | * @param status
45 | * @param message
46 | * @param record
47 | */
48 | public void publishEvent(Task task, Long taskFlowId, ConcurrentHashMap context, String status, String message, boolean record) throws TryLockException, TaskLogException {
49 | TaskFlowContextWrapper taskFlowContextWrapper = new TaskFlowContextWrapper(context);
50 | TaskContextWrapper taskContextWrapper = taskFlowContextWrapper.getTaskContextWrapper(task.getId().toString());
51 |
52 | TaskStatus taskStatus = new TaskStatus();
53 | taskStatus.setTask(task);
54 | taskStatus.setTaskFlowId(taskFlowId);
55 | taskStatus.setContext(taskContextWrapper.getContext());
56 | taskStatus.setStatus(status);
57 | taskStatus.setMessage(message);
58 | if (record) {
59 | String taskLogLock = ClusterConstants.getTaskLogLock(task.getId());
60 | boolean locked = false;
61 | try {
62 | locked = this.clusterController.tryLock(
63 | taskLogLock,
64 | clusterConfig.getTaskLogLockWaitTime(),
65 | clusterConfig.getTaskLogLockLeaseTime(),
66 | TimeUnit.SECONDS);
67 | if (!locked) {
68 | throw new TryLockException("Acquire the task log lock failed!");
69 | }
70 | Long taskFlowLogId = taskFlowContextWrapper.getValue(TaskFlowContextKey.LOG_ID, Long.class);
71 | boolean isRollback = taskFlowContextWrapper.getValue(TaskFlowContextKey.IS_ROLLBACK, Boolean.class);
72 | Long taskLogId = taskContextWrapper.getValue(TaskContextKey.TASK_LOG_ID, Long.class);
73 | String logFileId = taskContextWrapper.getValue(TaskContextKey.TASK_LOG_FILE_ID, String.class);
74 | TaskLog taskLog = this.taskLogger.get(taskFlowLogId, task.getId());
75 | boolean isNewLog = false;
76 | Date now = new Date();
77 | if (taskLog == null) {
78 | isNewLog = true;
79 | taskLog = new TaskLog();
80 | taskLog.setCreationTime(now);
81 | }
82 | taskLog.setLogId(taskLogId);
83 | taskLog.setTaskId(task.getId());
84 | taskLog.setTask(task);
85 | taskLog.setTaskFlowLogId(taskFlowLogId);
86 | taskLog.setTaskFlowId(taskFlowId);
87 | taskLog.setContext(taskContextWrapper.getContext());
88 | taskLog.setStatus(status);
89 | taskLog.setMessage(message);
90 | taskLog.setLogFileId(logFileId);
91 | taskLog.setRollback(isRollback);
92 | taskLog.setUpdateTime(now);
93 | if (isNewLog) {
94 | this.taskLogger.add(taskLog);
95 | } else {
96 | this.taskLogger.update(taskLog);
97 | }
98 | } finally {
99 | if (locked) {
100 | this.clusterController.unlock(taskLogLock);
101 | }
102 | }
103 | }
104 | TaskStatusChangeEvent taskStatusChangeEvent = new TaskStatusChangeEvent(this, taskStatus);
105 | this.eventPublisher.publishEvent(taskStatusChangeEvent);
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/exception/GenerateNodeIdException.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.exception;
2 |
3 | /**
4 | * 生成节点ID异常
5 | *
6 | * @author kpali
7 | */
8 | public class GenerateNodeIdException extends Exception {
9 | public GenerateNodeIdException() {
10 | super();
11 | }
12 |
13 | public GenerateNodeIdException(String message) {
14 | super(message);
15 | }
16 |
17 | public GenerateNodeIdException(Throwable cause) {
18 | super(cause);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/exception/InvalidCronExpressionException.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.exception;
2 |
3 | /**
4 | * 无效的cron表达式异常
5 | *
6 | * @author kpali
7 | */
8 | public class InvalidCronExpressionException extends Exception {
9 | public InvalidCronExpressionException() {
10 | super();
11 | }
12 |
13 | public InvalidCronExpressionException(String message) {
14 | super(message);
15 | }
16 |
17 | public InvalidCronExpressionException(Throwable cause) {
18 | super(cause);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/exception/InvalidTaskFlowException.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.exception;
2 |
3 | /**
4 | * 无效的任务流异常
5 | *
6 | * @author kpali
7 | */
8 | public class InvalidTaskFlowException extends Exception {
9 | public InvalidTaskFlowException() {
10 | super();
11 | }
12 |
13 | public InvalidTaskFlowException(String message) {
14 | super(message);
15 | }
16 |
17 | public InvalidTaskFlowException(Throwable cause) {
18 | super(cause);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/exception/TaskExecuteException.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.exception;
2 |
3 | /**
4 | * 任务执行异常
5 | *
6 | * @author kpali
7 | */
8 | public class TaskExecuteException extends Exception {
9 | public TaskExecuteException() {
10 | super();
11 | }
12 |
13 | public TaskExecuteException(String message) {
14 | super(message);
15 | }
16 |
17 | public TaskExecuteException(Throwable cause) {
18 | super(cause);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/exception/TaskFlowExecuteException.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.exception;
2 |
3 | /**
4 | * 任务流执行异常
5 | *
6 | * @author kpali
7 | */
8 | public class TaskFlowExecuteException extends Exception {
9 | public TaskFlowExecuteException() {
10 | super();
11 | }
12 |
13 | public TaskFlowExecuteException(String message) {
14 | super(message);
15 | }
16 |
17 | public TaskFlowExecuteException(Throwable cause) {
18 | super(cause);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/exception/TaskFlowInterruptedException.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.exception;
2 |
3 | /**
4 | * 任务流中断异常
5 | *
6 | * @author kpali
7 | */
8 | public class TaskFlowInterruptedException extends Exception {
9 | public TaskFlowInterruptedException() {
10 | super();
11 | }
12 |
13 | public TaskFlowInterruptedException(String message) {
14 | super(message);
15 | }
16 |
17 | public TaskFlowInterruptedException(Throwable cause) {
18 | super(cause);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/exception/TaskFlowLogException.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.exception;
2 |
3 | /**
4 | * 任务流日志异常
5 | *
6 | * @author kpali
7 | */
8 | public class TaskFlowLogException extends Exception {
9 | public TaskFlowLogException() {
10 | super();
11 | }
12 |
13 | public TaskFlowLogException(String message) {
14 | super(message);
15 | }
16 |
17 | public TaskFlowLogException(Throwable cause) {
18 | super(cause);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/exception/TaskFlowQueryException.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.exception;
2 |
3 | /**
4 | * 任务流查询异常
5 | *
6 | * @author kpali
7 | */
8 | public class TaskFlowQueryException extends Exception {
9 | public TaskFlowQueryException() {
10 | super();
11 | }
12 |
13 | public TaskFlowQueryException(String message) {
14 | super(message);
15 | }
16 |
17 | public TaskFlowQueryException(Throwable cause) {
18 | super(cause);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/exception/TaskFlowRollbackException.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.exception;
2 |
3 | /**
4 | * 任务流回滚异常
5 | *
6 | * @author kpali
7 | */
8 | public class TaskFlowRollbackException extends Exception {
9 | public TaskFlowRollbackException() {
10 | super();
11 | }
12 |
13 | public TaskFlowRollbackException(String message) {
14 | super(message);
15 | }
16 |
17 | public TaskFlowRollbackException(Throwable cause) {
18 | super(cause);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/exception/TaskFlowStopException.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.exception;
2 |
3 | /**
4 | * 任务流终止异常
5 | *
6 | * @author kpali
7 | */
8 | public class TaskFlowStopException extends Exception {
9 | public TaskFlowStopException() {
10 | super();
11 | }
12 |
13 | public TaskFlowStopException(String message) {
14 | super(message);
15 | }
16 |
17 | public TaskFlowStopException(Throwable cause) {
18 | super(cause);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/exception/TaskFlowTriggerException.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.exception;
2 |
3 | /**
4 | * 任务流触发异常
5 | *
6 | * @author kpali
7 | */
8 | public class TaskFlowTriggerException extends Exception {
9 | public TaskFlowTriggerException() {
10 | super();
11 | }
12 |
13 | public TaskFlowTriggerException(String message) {
14 | super(message);
15 | }
16 |
17 | public TaskFlowTriggerException(Throwable cause) {
18 | super(cause);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/exception/TaskInterruptedException.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.exception;
2 |
3 | /**
4 | * 任务中断异常
5 | *
6 | * @author kpali
7 | */
8 | public class TaskInterruptedException extends Exception {
9 | public TaskInterruptedException() {
10 | super();
11 | }
12 |
13 | public TaskInterruptedException(String message) {
14 | super(message);
15 | }
16 |
17 | public TaskInterruptedException(Throwable cause) {
18 | super(cause);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/exception/TaskLogException.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.exception;
2 |
3 | /**
4 | * 任务日志异常
5 | *
6 | * @author kpali
7 | */
8 | public class TaskLogException extends Exception {
9 | public TaskLogException() {
10 | super();
11 | }
12 |
13 | public TaskLogException(String message) {
14 | super(message);
15 | }
16 |
17 | public TaskLogException(Throwable cause) {
18 | super(cause);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/exception/TaskRollbackException.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.exception;
2 |
3 | /**
4 | * 任务回滚异常
5 | *
6 | * @author kpali
7 | */
8 | public class TaskRollbackException extends Exception {
9 | public TaskRollbackException() {
10 | super();
11 | }
12 |
13 | public TaskRollbackException(String message) {
14 | super(message);
15 | }
16 |
17 | public TaskRollbackException(Throwable cause) {
18 | super(cause);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/exception/TaskStopException.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.exception;
2 |
3 | /**
4 | * 任务终止异常
5 | *
6 | * @author kpali
7 | */
8 | public class TaskStopException extends Exception {
9 | public TaskStopException() {
10 | super();
11 | }
12 |
13 | public TaskStopException(String message) {
14 | super(message);
15 | }
16 |
17 | public TaskStopException(Throwable cause) {
18 | super(cause);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/exception/TryLockException.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.exception;
2 |
3 | /**
4 | * 尝试加锁异常
5 | *
6 | * @author kpali
7 | */
8 | public class TryLockException extends Exception {
9 | public TryLockException() {
10 | super();
11 | }
12 |
13 | public TryLockException(String message) {
14 | super(message);
15 | }
16 |
17 | public TryLockException(Throwable cause) {
18 | super(cause);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/executor/ITaskFlowExecutor.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.executor;
2 |
3 | import me.kpali.wolfflow.core.exception.TaskFlowExecuteException;
4 | import me.kpali.wolfflow.core.exception.TaskFlowInterruptedException;
5 | import me.kpali.wolfflow.core.exception.TaskFlowRollbackException;
6 | import me.kpali.wolfflow.core.model.TaskFlow;
7 |
8 | import java.util.concurrent.ConcurrentHashMap;
9 |
10 | /**
11 | * 任务流执行器接口
12 | *
13 | * @author kpali
14 | */
15 | public interface ITaskFlowExecutor {
16 | /**
17 | * 任务流执行前置处理
18 | *
19 | * @param taskFlow
20 | * @param context
21 | * @throws TaskFlowExecuteException
22 | */
23 | void beforeExecute(TaskFlow taskFlow, ConcurrentHashMap context) throws TaskFlowExecuteException;
24 |
25 | /**
26 | * 任务流执行
27 | *
28 | * @param taskFlow
29 | * @param context
30 | * @throws TaskFlowExecuteException
31 | * @throws TaskFlowInterruptedException
32 | */
33 | void execute(TaskFlow taskFlow, ConcurrentHashMap context) throws TaskFlowExecuteException, TaskFlowInterruptedException;
34 |
35 | /**
36 | * 任务流执行后置处理
37 | *
38 | * @param taskFlow
39 | * @param context
40 | * @throws TaskFlowExecuteException
41 | */
42 | void afterExecute(TaskFlow taskFlow, ConcurrentHashMap context) throws TaskFlowExecuteException;
43 |
44 | /**
45 | * 任务流回滚前置处理
46 | *
47 | * @param taskFlow
48 | * @param context
49 | * @throws TaskFlowRollbackException
50 | */
51 | void beforeRollback(TaskFlow taskFlow, ConcurrentHashMap context) throws TaskFlowRollbackException;
52 |
53 | /**
54 | * 任务流回滚
55 | *
56 | * @param taskFlow
57 | * @param context
58 | * @throws TaskFlowRollbackException
59 | * @throws TaskFlowInterruptedException
60 | */
61 | void rollback(TaskFlow taskFlow, ConcurrentHashMap context) throws TaskFlowRollbackException, TaskFlowInterruptedException;
62 |
63 | /**
64 | * 任务流执行后置处理
65 | *
66 | * @param taskFlow
67 | * @param context
68 | * @throws TaskFlowRollbackException
69 | */
70 | void afterRollback(TaskFlow taskFlow, ConcurrentHashMap context) throws TaskFlowRollbackException;
71 | }
72 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/launcher/Launcher.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.launcher;
2 |
3 | import me.kpali.wolfflow.core.cluster.IClusterController;
4 | import me.kpali.wolfflow.core.monitor.IMonitor;
5 | import me.kpali.wolfflow.core.scheduler.ITaskFlowScheduler;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.stereotype.Component;
8 |
9 | /**
10 | * 启动器
11 | *
12 | * @author kpali
13 | */
14 | @Component
15 | public class Launcher {
16 | @Autowired
17 | IMonitor monitor;
18 | @Autowired
19 | ITaskFlowScheduler taskFlowScheduler;
20 | @Autowired
21 | IClusterController clusterController;
22 |
23 | public void startup() {
24 | this.monitor.init();
25 | this.taskFlowScheduler.startup();
26 | this.clusterController.startup();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/logger/ITaskFlowLogger.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.logger;
2 |
3 | import me.kpali.wolfflow.core.exception.TaskFlowLogException;
4 | import me.kpali.wolfflow.core.model.TaskFlowLog;
5 |
6 | import java.util.List;
7 |
8 | /**
9 | * 任务流日志器
10 | *
11 | * @author kpali
12 | */
13 | public interface ITaskFlowLogger {
14 | /**
15 | * 根据任务流ID获取日志列表
16 | *
17 | * @param taskFlowId
18 | * @return
19 | * @throws TaskFlowLogException
20 | */
21 | List list(Long taskFlowId) throws TaskFlowLogException;
22 |
23 | /**
24 | * 根据任务流ID获取最后的任务流日志
25 | *
26 | * @param taskFlowId
27 | * @return
28 | * @throws TaskFlowLogException
29 | */
30 | TaskFlowLog last(Long taskFlowId) throws TaskFlowLogException;
31 |
32 | /**
33 | * 根据日志ID获取任务流日志
34 | *
35 | * @param taskFlowLogId
36 | * @return
37 | * @throws TaskFlowLogException
38 | */
39 | TaskFlowLog get(Long taskFlowLogId) throws TaskFlowLogException;
40 |
41 | /**
42 | * 新增任务流日志
43 | *
44 | * @param taskFlowLog
45 | * @throws TaskFlowLogException
46 | */
47 | void add(TaskFlowLog taskFlowLog) throws TaskFlowLogException;
48 |
49 | /**
50 | * 更新任务流日志
51 | *
52 | * @param taskFlowLog
53 | * @throws TaskFlowLogException
54 | */
55 | void update(TaskFlowLog taskFlowLog) throws TaskFlowLogException;
56 |
57 | /**
58 | * 根据日志ID删除任务流日志
59 | *
60 | * @param taskFlowLogId
61 | * @throws TaskFlowLogException
62 | */
63 | void delete(Long taskFlowLogId) throws TaskFlowLogException;
64 |
65 | /**
66 | * 根据任务流ID删除所有任务流日志
67 | *
68 | * @param taskFlowId
69 | * @throws TaskFlowLogException
70 | */
71 | void deleteByTaskFlowId(Long taskFlowId) throws TaskFlowLogException;
72 |
73 | /**
74 | * 查询是否正在处理中
75 | *
76 | * @param taskFlowLogId
77 | * @return
78 | * @throws TaskFlowLogException
79 | */
80 | boolean isInProgress(Long taskFlowLogId) throws TaskFlowLogException;
81 |
82 | /**
83 | * 查询是否正在处理中
84 | *
85 | * @param taskFlowLog
86 | * @return
87 | * @throws TaskFlowLogException
88 | */
89 | boolean isInProgress(TaskFlowLog taskFlowLog) throws TaskFlowLogException;
90 | }
91 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/logger/ITaskLogger.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.logger;
2 |
3 | import me.kpali.wolfflow.core.exception.TaskLogException;
4 | import me.kpali.wolfflow.core.model.TaskLog;
5 | import me.kpali.wolfflow.core.model.TaskLogResult;
6 |
7 | import java.util.List;
8 |
9 | /**
10 | * 任务日志器
11 | *
12 | * @author kpali
13 | */
14 | public interface ITaskLogger {
15 | /**
16 | * 根据任务流日志ID获取任务日志列表
17 | *
18 | * @param taskFlowLogId
19 | * @return
20 | * @throws TaskLogException
21 | */
22 | List list(Long taskFlowLogId) throws TaskLogException;
23 |
24 | /**
25 | * 根据任务流日志ID和任务ID获取任务日志
26 | *
27 | * @param taskFlowLogId
28 | * @param taskId
29 | * @return
30 | * @throws TaskLogException
31 | */
32 | TaskLog get(Long taskFlowLogId, Long taskId) throws TaskLogException;
33 |
34 | /**
35 | * 新增任务日志
36 | *
37 | * @param taskLog
38 | * @throws TaskLogException
39 | */
40 | void add(TaskLog taskLog) throws TaskLogException;
41 |
42 | /**
43 | * 更新任务日志
44 | *
45 | * @param taskLog
46 | * @throws TaskLogException
47 | */
48 | void update(TaskLog taskLog) throws TaskLogException;
49 |
50 | /**
51 | * 根据任务ID获取最后一次执行的日志
52 | *
53 | * @param taskId
54 | * @throws TaskLogException
55 | */
56 | TaskLog getLastExecuteLog(Long taskId) throws TaskLogException;
57 |
58 | /**
59 | * 根据任务流日志ID删除任务日志
60 | *
61 | * @param taskFlowLogId
62 | * @throws TaskLogException
63 | */
64 | void deleteByTaskFlowLogId(Long taskFlowLogId) throws TaskLogException;
65 |
66 | /**
67 | * 记录日志内容,如果日志内容不存在则新增,存在则追加
68 | *
69 | * @param logFileId
70 | * @param logContent
71 | * @param end
72 | * @return 当前日志总行数
73 | * @throws TaskLogException
74 | */
75 | int log(String logFileId, String logContent, Boolean end) throws TaskLogException;
76 |
77 | /**
78 | * 查询日志内容
79 | *
80 | * @param logFileId
81 | * @param fromLineNum
82 | * @return
83 | * @throws TaskLogException
84 | */
85 | TaskLogResult query(String logFileId, Integer fromLineNum) throws TaskLogException;
86 |
87 | /**
88 | * 新增或更新任务状态
89 | *
90 | * @param taskStatus
91 | * @throws TaskLogException
92 | */
93 | void putTaskStatus(TaskLog taskStatus) throws TaskLogException;
94 |
95 | /**
96 | * 根据任务ID获取任务状态
97 | *
98 | * @param taskId
99 | * @throws TaskLogException
100 | */
101 | TaskLog getTaskStatus(Long taskId) throws TaskLogException;
102 |
103 | /**
104 | * 根据任务流ID获取任务状态列表
105 | *
106 | * @param taskFlowId
107 | * @return
108 | * @throws TaskLogException
109 | */
110 | List listTaskStatus(Long taskFlowId) throws TaskLogException;
111 |
112 | /**
113 | * 根据任务ID删除任务状态
114 | *
115 | * @param taskId
116 | * @throws TaskLogException
117 | */
118 | void deleteTaskStatus(Long taskId) throws TaskLogException;
119 |
120 | /**
121 | * 查询是否正在处理中
122 | *
123 | * @param taskLog
124 | * @return
125 | * @throws TaskLogException
126 | */
127 | boolean isInProgress(TaskLog taskLog) throws TaskLogException;
128 |
129 | /**
130 | * 是否可以回滚
131 | *
132 | * @param taskLog
133 | * @return
134 | * @throws TaskLogException
135 | */
136 | boolean canRollback(TaskLog taskLog) throws TaskLogException;
137 | }
138 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/model/ClusterConstants.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.model;
2 |
3 | /**
4 | * 集群常量
5 | *
6 | * @author kpali
7 | */
8 | public class ClusterConstants {
9 | public static final String GENERATE_NODE_ID_LOCK = "GenerateNodeIdLock";
10 | public static final String TASK_FLOW_LOG_LOCK_PREFIX = "TaskFlowLogLock_";
11 | public static final String TASK_LOG_LOCK_PREFIX = "TaskLogLock_";
12 | public static final String CRON_TASK_FLOW_SCAN_LOCK = "CronTaskFlowScanLock";
13 |
14 | public static String getTaskFlowLogLock(Long taskFlowId) {
15 | return TASK_FLOW_LOG_LOCK_PREFIX + String.valueOf(taskFlowId);
16 | }
17 |
18 | public static String getTaskLogLock(Long taskId) {
19 | return TASK_LOG_LOCK_PREFIX + String.valueOf(taskId);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/model/DeliveryContextKey.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.model;
2 |
3 | /**
4 | * 投递上下文
5 | *
6 | * @author kpali
7 | */
8 | public class DeliveryContextKey {
9 | }
10 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/model/Link.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.model;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * 任务之间的连接
7 | *
8 | * @author kpali
9 | */
10 | public class Link implements Serializable {
11 | public Link() {
12 | }
13 |
14 | public Link(Long source, Long target) {
15 | this.source = source;
16 | this.target = target;
17 | }
18 |
19 | private static final long serialVersionUID = -4190148088560825591L;
20 |
21 | private Long source;
22 | private Long target;
23 |
24 | public Long getSource() {
25 | return source;
26 | }
27 |
28 | public void setSource(Long source) {
29 | this.source = source;
30 | }
31 |
32 | public Long getTarget() {
33 | return target;
34 | }
35 |
36 | public void setTarget(Long target) {
37 | this.target = target;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/model/ManualConfirmed.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.model;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * 手工确认信息
7 | *
8 | * @author kpali
9 | */
10 | public class ManualConfirmed implements Serializable {
11 | private static final long serialVersionUID = 1048105386454641255L;
12 |
13 | public ManualConfirmed() {
14 | }
15 |
16 | public ManualConfirmed(Long taskLogId, Boolean success, String message) {
17 | this.taskLogId = taskLogId;
18 | this.success = success;
19 | this.message = message;
20 | }
21 |
22 | private Long taskLogId;
23 | private Boolean success;
24 | private String message;
25 |
26 | public Long getTaskLogId() {
27 | return taskLogId;
28 | }
29 |
30 | public void setTaskLogId(Long taskLogId) {
31 | this.taskLogId = taskLogId;
32 | }
33 |
34 | public Boolean getSuccess() {
35 | return success;
36 | }
37 |
38 | public void setSuccess(Boolean success) {
39 | this.success = success;
40 | }
41 |
42 | public String getMessage() {
43 | return message;
44 | }
45 |
46 | public void setMessage(String message) {
47 | this.message = message;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/model/Task.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.model;
2 |
3 | import me.kpali.wolfflow.core.exception.TaskExecuteException;
4 | import me.kpali.wolfflow.core.exception.TaskInterruptedException;
5 | import me.kpali.wolfflow.core.exception.TaskRollbackException;
6 | import me.kpali.wolfflow.core.exception.TaskStopException;
7 |
8 | import java.io.Serializable;
9 | import java.util.concurrent.ConcurrentHashMap;
10 |
11 | /**
12 | * 任务
13 | *
14 | * @author kpali
15 | */
16 | public class Task implements Serializable {
17 | private static final long serialVersionUID = 1097164523753393528L;
18 |
19 | private Long id;
20 | /**
21 | * 是否手工任务
22 | */
23 | private boolean manual = false;
24 |
25 | public Long getId() {
26 | return id;
27 | }
28 |
29 | public void setId(Long id) {
30 | this.id = id;
31 | }
32 |
33 | public boolean getManual() {
34 | return this.manual;
35 | }
36 |
37 | public void setManual(boolean manual) {
38 | this.manual = manual;
39 | }
40 |
41 | public void executePreCheck(ConcurrentHashMap context) throws TaskExecuteException {
42 | // 不作任何操作
43 | }
44 |
45 | public void beforeExecute(ConcurrentHashMap context) throws TaskExecuteException {
46 | // 不做任何操作
47 | }
48 |
49 | public void execute(ConcurrentHashMap context) throws TaskExecuteException, TaskInterruptedException {
50 | // 不做任何操作
51 | }
52 |
53 | public void afterExecute(ConcurrentHashMap context) throws TaskExecuteException {
54 | // 不做任何操作
55 | }
56 |
57 | public void beforeRollback(ConcurrentHashMap context) throws TaskRollbackException {
58 | // 不做任何操作
59 | }
60 |
61 | public void rollbackPreCheck(ConcurrentHashMap context) throws TaskRollbackException {
62 | // 不作任何操作
63 | }
64 |
65 | public void rollback(ConcurrentHashMap context) throws TaskRollbackException, TaskInterruptedException {
66 | // 不做任何操作
67 | }
68 |
69 | public void afterRollback(ConcurrentHashMap context) throws TaskRollbackException {
70 | // 不做任何操作
71 | }
72 |
73 | public void stop(ConcurrentHashMap context) throws TaskStopException {
74 | // 不做任何操作
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/model/TaskContextKey.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.model;
2 |
3 | /**
4 | * 任务上下文
5 | *
6 | * @author kpali
7 | */
8 | public class TaskContextKey {
9 | public static final String LOG_ID = "logId";
10 | public static final String TASK_LOG_ID = "logId";
11 | public static final String TASK_LOG_FILE_ID = "logFileId";
12 | public static final String TASK_LAST_EXECUTE_LOG_ID = "lastExecuteLogId";
13 | public static final String PARENT_TASK_ID_LIST = "parentTaskIdList";
14 | }
15 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/model/TaskFlow.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.model;
2 |
3 | import java.io.Serializable;
4 | import java.util.List;
5 |
6 | /**
7 | * 任务流
8 | *
9 | * @author kpali
10 | */
11 | public class TaskFlow implements Serializable {
12 | private static final long serialVersionUID = 5077291498959687573L;
13 |
14 | private Long id;
15 | private List taskList;
16 | private List linkList;
17 | private String cron;
18 | private Long fromTaskId;
19 | private Long toTaskId;
20 |
21 | public Long getId() {
22 | return id;
23 | }
24 |
25 | public void setId(Long id) {
26 | this.id = id;
27 | }
28 |
29 | public List getTaskList() {
30 | return taskList;
31 | }
32 |
33 | public void setTaskList(List taskList) {
34 | this.taskList = taskList;
35 | }
36 |
37 | public List getLinkList() {
38 | return linkList;
39 | }
40 |
41 | public void setLinkList(List linkList) {
42 | this.linkList = linkList;
43 | }
44 |
45 | public String getCron() {
46 | return cron;
47 | }
48 |
49 | public void setCron(String cron) {
50 | this.cron = cron;
51 | }
52 |
53 | public Long getFromTaskId() {
54 | return fromTaskId;
55 | }
56 |
57 | public void setFromTaskId(Long fromTaskId) {
58 | this.fromTaskId = fromTaskId;
59 | }
60 |
61 | public Long getToTaskId() {
62 | return toTaskId;
63 | }
64 |
65 | public void setToTaskId(Long toTaskId) {
66 | this.toTaskId = toTaskId;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/model/TaskFlowContextKey.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.model;
2 |
3 | /**
4 | * 任务流上下文
5 | *
6 | * @author kpali
7 | */
8 | public class TaskFlowContextKey {
9 | public static final String TASK_FLOW_ID = "taskFlowId";
10 | public static final String IS_ROLLBACK = "isRollback";
11 | public static final String FROM_TASK_ID = "fromTaskId";
12 | public static final String TO_TASK_ID = "toTaskId";
13 | public static final String LOG_ID = "logId";
14 | public static final String PARAMS = "params";
15 | public static final String DELIVERY_CONTEXT = "deliveryContext";
16 | public static final String EXECUTE_TASK_FLOW = "executeTaskFlow";
17 | public static final String ROLLBACK_TASK_FLOW = "rollbackTaskFlow";
18 | public static final String TASK_CONTEXTS = "taskContexts";
19 | public static final String EXECUTED_BY_NODE = "executedByNode";
20 | }
21 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/model/TaskFlowExecRequest.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.model;
2 |
3 | import java.io.Serializable;
4 | import java.util.concurrent.ConcurrentHashMap;
5 |
6 | /**
7 | * 任务流执行请求
8 | *
9 | * @author kpali
10 | */
11 | public class TaskFlowExecRequest implements Serializable {
12 | private static final long serialVersionUID = 8484106840325360892L;
13 |
14 | public TaskFlowExecRequest() {
15 | }
16 |
17 | public TaskFlowExecRequest(Long taskFlowId, ConcurrentHashMap context) {
18 | this.taskFlowId = taskFlowId;
19 | this.context = context;
20 | }
21 |
22 | private Long taskFlowId;
23 | private ConcurrentHashMap context;
24 |
25 | public Long getTaskFlowId() {
26 | return taskFlowId;
27 | }
28 |
29 | public void setTaskFlowId(Long taskFlowId) {
30 | this.taskFlowId = taskFlowId;
31 | }
32 |
33 | public ConcurrentHashMap getContext() {
34 | return context;
35 | }
36 |
37 | public void setContext(ConcurrentHashMap context) {
38 | this.context = context;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/model/TaskFlowLog.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.model;
2 |
3 | import java.io.Serializable;
4 | import java.util.Date;
5 | import java.util.concurrent.ConcurrentHashMap;
6 |
7 | /**
8 | * 任务流日志
9 | *
10 | * @author kpali
11 | */
12 | public class TaskFlowLog implements Serializable {
13 | private static final long serialVersionUID = -875754396936412243L;
14 |
15 | private Long logId;
16 | private Long taskFlowId;
17 | private TaskFlow taskFlow;
18 | private ConcurrentHashMap context;
19 | private String status;
20 | private String message;
21 | private boolean rollback;
22 | private Date creationTime;
23 | private Date updateTime;
24 |
25 | public Long getLogId() {
26 | return logId;
27 | }
28 |
29 | public void setLogId(Long logId) {
30 | this.logId = logId;
31 | }
32 |
33 | public Long getTaskFlowId() {
34 | return taskFlowId;
35 | }
36 |
37 | public void setTaskFlowId(Long taskFlowId) {
38 | this.taskFlowId = taskFlowId;
39 | }
40 |
41 | public TaskFlow getTaskFlow() {
42 | return taskFlow;
43 | }
44 |
45 | public void setTaskFlow(TaskFlow taskFlow) {
46 | this.taskFlow = taskFlow;
47 | }
48 |
49 | public ConcurrentHashMap getContext() {
50 | return context;
51 | }
52 |
53 | public void setContext(ConcurrentHashMap context) {
54 | this.context = context;
55 | }
56 |
57 | public String getStatus() {
58 | return status;
59 | }
60 |
61 | public void setStatus(String status) {
62 | this.status = status;
63 | }
64 |
65 | public String getMessage() {
66 | return message;
67 | }
68 |
69 | public void setMessage(String message) {
70 | this.message = message;
71 | }
72 |
73 | public boolean getRollback() {
74 | return rollback;
75 | }
76 |
77 | public void setRollback(boolean rollback) {
78 | this.rollback = rollback;
79 | }
80 |
81 | public Date getCreationTime() {
82 | return creationTime;
83 | }
84 |
85 | public void setCreationTime(Date creationTime) {
86 | this.creationTime = creationTime;
87 | }
88 |
89 | public Date getUpdateTime() {
90 | return updateTime;
91 | }
92 |
93 | public void setUpdateTime(Date updateTime) {
94 | this.updateTime = updateTime;
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/model/TaskFlowStatus.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.model;
2 |
3 | import java.io.Serializable;
4 | import java.util.concurrent.ConcurrentHashMap;
5 |
6 | /**
7 | * 任务流状态
8 | *
9 | * @author kpali
10 | */
11 | public class TaskFlowStatus implements Serializable {
12 | private static final long serialVersionUID = 4373673109768512258L;
13 |
14 | private TaskFlow taskFlow;
15 | private ConcurrentHashMap context;
16 | private String status;
17 | private String message;
18 |
19 | public TaskFlow getTaskFlow() {
20 | return taskFlow;
21 | }
22 |
23 | public void setTaskFlow(TaskFlow taskFlow) {
24 | this.taskFlow = taskFlow;
25 | }
26 |
27 | public ConcurrentHashMap getContext() {
28 | return context;
29 | }
30 |
31 | public void setContext(ConcurrentHashMap context) {
32 | this.context = context;
33 | }
34 |
35 | public String getStatus() {
36 | return status;
37 | }
38 |
39 | public void setStatus(String status) {
40 | this.status = status;
41 | }
42 |
43 | public String getMessage() {
44 | return message;
45 | }
46 |
47 | public void setMessage(String message) {
48 | this.message = message;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/model/TaskLog.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.model;
2 |
3 | import java.io.Serializable;
4 | import java.util.Date;
5 | import java.util.concurrent.ConcurrentHashMap;
6 |
7 | /**
8 | * 任务日志
9 | *
10 | * @author kpali
11 | */
12 | public class TaskLog implements Serializable {
13 | private static final long serialVersionUID = 14370329912885306L;
14 |
15 | private Long logId;
16 | private Long taskFlowLogId;
17 | private Long taskId;
18 | private Task task;
19 | private Long taskFlowId;
20 | private ConcurrentHashMap context;
21 | private String status;
22 | private String message;
23 | private String logFileId;
24 | private boolean rollback;
25 | private Date creationTime;
26 | private Date updateTime;
27 |
28 | public Long getLogId() {
29 | return logId;
30 | }
31 |
32 | public void setLogId(Long logId) {
33 | this.logId = logId;
34 | }
35 |
36 | public Long getTaskFlowLogId() {
37 | return taskFlowLogId;
38 | }
39 |
40 | public void setTaskFlowLogId(Long taskFlowLogId) {
41 | this.taskFlowLogId = taskFlowLogId;
42 | }
43 |
44 | public Long getTaskId() {
45 | return taskId;
46 | }
47 |
48 | public void setTaskId(Long taskId) {
49 | this.taskId = taskId;
50 | }
51 |
52 | public Task getTask() {
53 | return task;
54 | }
55 |
56 | public void setTask(Task task) {
57 | this.task = task;
58 | }
59 |
60 | public Long getTaskFlowId() {
61 | return taskFlowId;
62 | }
63 |
64 | public void setTaskFlowId(Long taskFlowId) {
65 | this.taskFlowId = taskFlowId;
66 | }
67 |
68 | public ConcurrentHashMap getContext() {
69 | return context;
70 | }
71 |
72 | public void setContext(ConcurrentHashMap context) {
73 | this.context = context;
74 | }
75 |
76 | public String getStatus() {
77 | return status;
78 | }
79 |
80 | public void setStatus(String status) {
81 | this.status = status;
82 | }
83 |
84 | public String getMessage() {
85 | return message;
86 | }
87 |
88 | public void setMessage(String message) {
89 | this.message = message;
90 | }
91 |
92 | public String getLogFileId() {
93 | return logFileId;
94 | }
95 |
96 | public void setLogFileId(String logFileId) {
97 | this.logFileId = logFileId;
98 | }
99 |
100 | public boolean getRollback() {
101 | return rollback;
102 | }
103 |
104 | public void setRollback(boolean rollback) {
105 | this.rollback = rollback;
106 | }
107 |
108 | public Date getCreationTime() {
109 | return creationTime;
110 | }
111 |
112 | public void setCreationTime(Date creationTime) {
113 | this.creationTime = creationTime;
114 | }
115 |
116 | public Date getUpdateTime() {
117 | return updateTime;
118 | }
119 |
120 | public void setUpdateTime(Date updateTime) {
121 | this.updateTime = updateTime;
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/model/TaskLogLine.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.model;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * 任务日志行
7 | *
8 | * @author kpali
9 | */
10 | public class TaskLogLine implements Serializable {
11 | private static final long serialVersionUID = -5469833248990193615L;
12 |
13 | private Integer lineNum;
14 | private String line;
15 | private Boolean end;
16 |
17 | public Integer getLineNum() {
18 | return lineNum;
19 | }
20 |
21 | public void setLineNum(Integer lineNum) {
22 | this.lineNum = lineNum;
23 | }
24 |
25 | public String getLine() {
26 | return line;
27 | }
28 |
29 | public void setLine(String line) {
30 | this.line = line;
31 | }
32 |
33 | public Boolean getEnd() {
34 | return end;
35 | }
36 |
37 | public void setEnd(Boolean end) {
38 | this.end = end;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/model/TaskLogResult.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.model;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * 任务日志结果
7 | *
8 | * @author kpali
9 | */
10 | public class TaskLogResult implements Serializable {
11 | private static final long serialVersionUID = -237328970035347440L;
12 |
13 | private Integer fromLineNum;
14 | private Integer toLineNum;
15 | private String logContent;
16 | private Boolean end;
17 |
18 | public Integer getFromLineNum() {
19 | return fromLineNum;
20 | }
21 |
22 | public void setFromLineNum(Integer fromLineNum) {
23 | this.fromLineNum = fromLineNum;
24 | }
25 |
26 | public Integer getToLineNum() {
27 | return toLineNum;
28 | }
29 |
30 | public void setToLineNum(Integer toLineNum) {
31 | this.toLineNum = toLineNum;
32 | }
33 |
34 | public String getLogContent() {
35 | return logContent;
36 | }
37 |
38 | public void setLogContent(String logContent) {
39 | this.logContent = logContent;
40 | }
41 |
42 | public Boolean getEnd() {
43 | return end;
44 | }
45 |
46 | public void setEnd(Boolean end) {
47 | this.end = end;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/model/TaskStatus.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.model;
2 |
3 | import java.io.Serializable;
4 | import java.util.concurrent.ConcurrentHashMap;
5 |
6 | /**
7 | * 任务状态
8 | *
9 | * @author kpali
10 | */
11 | public class TaskStatus implements Serializable {
12 | private static final long serialVersionUID = -933124446911559604L;
13 |
14 | private Task task;
15 | private Long taskFlowId;
16 | private ConcurrentHashMap context;
17 | private String status;
18 | private String message;
19 |
20 | public Task getTask() {
21 | return task;
22 | }
23 |
24 | public void setTask(Task task) {
25 | this.task = task;
26 | }
27 |
28 | public Long getTaskFlowId() {
29 | return taskFlowId;
30 | }
31 |
32 | public void setTaskFlowId(Long taskFlowId) {
33 | this.taskFlowId = taskFlowId;
34 | }
35 |
36 | public ConcurrentHashMap getContext() {
37 | return context;
38 | }
39 |
40 | public void setContext(ConcurrentHashMap context) {
41 | this.context = context;
42 | }
43 |
44 | public String getStatus() {
45 | return status;
46 | }
47 |
48 | public void setStatus(String status) {
49 | this.status = status;
50 | }
51 |
52 | public String getMessage() {
53 | return message;
54 | }
55 |
56 | public void setMessage(String message) {
57 | this.message = message;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/monitor/IMonitor.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.monitor;
2 |
3 | import java.util.concurrent.ExecutorService;
4 |
5 | /**
6 | * 监控器
7 | *
8 | * @author kpali
9 | */
10 | public interface IMonitor {
11 | /**
12 | * 监控器初始化
13 | */
14 | void init();
15 |
16 | /**
17 | * 监控线程池
18 | *
19 | * @param executor
20 | * @param executorName
21 | */
22 | void monitor(ExecutorService executor, String executorName);
23 |
24 | /**
25 | * 获取监控指标
26 | *
27 | * @return
28 | */
29 | String scrape();
30 | }
31 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/monitor/impl/DefaultMonitor.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.monitor.impl;
2 |
3 | import io.micrometer.core.instrument.MeterRegistry;
4 | import io.micrometer.core.instrument.Metrics;
5 | import io.micrometer.core.instrument.binder.jvm.*;
6 | import io.micrometer.core.instrument.binder.system.ProcessorMetrics;
7 | import io.micrometer.prometheus.PrometheusConfig;
8 | import io.micrometer.prometheus.PrometheusMeterRegistry;
9 | import me.kpali.wolfflow.core.monitor.IMonitor;
10 | import org.springframework.beans.factory.annotation.Value;
11 | import org.springframework.stereotype.Component;
12 |
13 | import java.util.Collections;
14 | import java.util.List;
15 | import java.util.concurrent.ExecutorService;
16 | import java.util.stream.Collectors;
17 |
18 | /**
19 | * 监控器的默认实现
20 | *
21 | * @author kpali
22 | */
23 | @Component
24 | public class DefaultMonitor implements IMonitor {
25 | @Value("${spring.application.name:wolf-flow}")
26 | String applicationName;
27 |
28 | @Override
29 | public void init() {
30 | PrometheusMeterRegistry prometheusRegistry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);
31 | prometheusRegistry.config().commonTags("application", applicationName);
32 | Metrics.addRegistry(prometheusRegistry);
33 |
34 | new ClassLoaderMetrics().bindTo(Metrics.globalRegistry);
35 | new JvmMemoryMetrics().bindTo(Metrics.globalRegistry);
36 | new JvmGcMetrics().bindTo(Metrics.globalRegistry);
37 | new ProcessorMetrics().bindTo(Metrics.globalRegistry);
38 | new JvmThreadMetrics().bindTo(Metrics.globalRegistry);
39 | }
40 |
41 | @Override
42 | public void monitor(ExecutorService executor, String executorName) {
43 | new ExecutorServiceMetrics(executor, executorName, Collections.emptyList()).bindTo(Metrics.globalRegistry);
44 | }
45 |
46 | @Override
47 | public String scrape() {
48 | List meterRegistries = Metrics.globalRegistry.getRegistries()
49 | .stream()
50 | .filter(meterRegistry -> meterRegistry instanceof PrometheusMeterRegistry)
51 | .collect(Collectors.toList());
52 | for (MeterRegistry registry : meterRegistries) {
53 | if (registry instanceof PrometheusMeterRegistry) {
54 | return ((PrometheusMeterRegistry) registry).scrape();
55 | }
56 | }
57 | return "";
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/querier/ITaskFlowQuerier.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.querier;
2 |
3 | import me.kpali.wolfflow.core.exception.TaskFlowQueryException;
4 | import me.kpali.wolfflow.core.model.TaskFlow;
5 |
6 | import java.util.List;
7 |
8 | /**
9 | * 任务流查询器
10 | *
11 | * @author kpali
12 | */
13 | public interface ITaskFlowQuerier {
14 |
15 | /**
16 | * 根据任务流ID获取任务流
17 | *
18 | * @param taskFlowId
19 | * @return
20 | * @throws TaskFlowQueryException
21 | */
22 | TaskFlow getTaskFlow(Long taskFlowId) throws TaskFlowQueryException;
23 |
24 | /**
25 | * 获取定时任务流列表
26 | *
27 | * @return
28 | * @throws TaskFlowQueryException
29 | */
30 | List listCronTaskFlow() throws TaskFlowQueryException;
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/querier/impl/DefaultTaskFlowQuerier.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.querier.impl;
2 |
3 | import me.kpali.wolfflow.core.querier.ITaskFlowQuerier;
4 | import me.kpali.wolfflow.core.exception.TaskFlowQueryException;
5 | import me.kpali.wolfflow.core.model.TaskFlow;
6 | import org.springframework.stereotype.Component;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * 任务流查询器的默认实现
12 | *
13 | * @author kpali
14 | */
15 | @Component
16 | public class DefaultTaskFlowQuerier implements ITaskFlowQuerier {
17 | @Override
18 | public TaskFlow getTaskFlow(Long taskFlowId) throws TaskFlowQueryException {
19 | return null;
20 | }
21 |
22 | @Override
23 | public List listCronTaskFlow() throws TaskFlowQueryException {
24 | return null;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/scheduler/ITaskFlowScheduler.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.scheduler;
2 |
3 | import me.kpali.wolfflow.core.exception.TaskFlowStopException;
4 | import me.kpali.wolfflow.core.exception.TaskFlowTriggerException;
5 |
6 | import java.util.concurrent.ConcurrentHashMap;
7 |
8 | /**
9 | * 任务流调度器
10 | *
11 | * @author kpali
12 | */
13 | public interface ITaskFlowScheduler {
14 | /**
15 | * 启动任务流调度器
16 | */
17 | void startup();
18 |
19 | /**
20 | * 执行任务流
21 | *
22 | * @param taskFlowId
23 | * @param params
24 | * @return taskFlowLogId
25 | * @throws TaskFlowTriggerException
26 | */
27 | long execute(Long taskFlowId, ConcurrentHashMap params) throws TaskFlowTriggerException;
28 |
29 | /**
30 | * 执行任务流,执行指定任务
31 | *
32 | * @param taskFlowId
33 | * @param taskId
34 | * @param params
35 | * @return taskFlowLogId
36 | * @throws TaskFlowTriggerException
37 | */
38 | long execute(Long taskFlowId, Long taskId, ConcurrentHashMap params) throws TaskFlowTriggerException;
39 |
40 | /**
41 | * 执行任务流,从指定任务开始
42 | *
43 | * @param taskFlowId
44 | * @param fromTaskId
45 | * @param params
46 | * @return taskFlowLogId
47 | * @throws TaskFlowTriggerException
48 | */
49 | long executeFrom(Long taskFlowId, Long fromTaskId, ConcurrentHashMap params) throws TaskFlowTriggerException;
50 |
51 | /**
52 | * 执行任务流,到指定任务结束
53 | *
54 | * @param taskFlowId
55 | * @param toTaskId
56 | * @param params
57 | * @return taskFlowLogId
58 | * @throws TaskFlowTriggerException
59 | */
60 | long executeTo(Long taskFlowId, Long toTaskId, ConcurrentHashMap params) throws TaskFlowTriggerException;
61 |
62 | /**
63 | * 回滚任务流
64 | *
65 | * @param taskFlowId
66 | * @param params
67 | * @return taskFlowLogId
68 | * @throws TaskFlowTriggerException
69 | */
70 | long rollback(Long taskFlowId, ConcurrentHashMap params) throws TaskFlowTriggerException;
71 |
72 | /**
73 | * 停止任务流
74 | *
75 | * @param taskFlowLogId
76 | * @throws TaskFlowStopException
77 | */
78 | void stop(Long taskFlowLogId) throws TaskFlowStopException;
79 | }
80 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/scheduler/impl/quartz/MyDynamicScheduler.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.scheduler.impl.quartz;
2 |
3 | import org.quartz.*;
4 | import org.quartz.impl.matchers.GroupMatcher;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import org.springframework.util.Assert;
8 |
9 | import java.util.Date;
10 | import java.util.List;
11 | import java.util.Map;
12 | import java.util.Set;
13 |
14 | /**
15 | * 动态调度器
16 | *
17 | * @author kpali
18 | */
19 | public class MyDynamicScheduler {
20 |
21 | public MyDynamicScheduler() {
22 | }
23 |
24 | private static final Logger logger = LoggerFactory.getLogger(MyDynamicScheduler.class);
25 | private static Scheduler scheduler;
26 |
27 | public void setScheduler(Scheduler scheduler) {
28 | MyDynamicScheduler.scheduler = scheduler;
29 | }
30 |
31 | public void start() throws Exception {
32 | Assert.notNull(scheduler, "quartz scheduler is null");
33 | logger.info("Quartz scheduler initialization completed.");
34 | }
35 |
36 | public void destroy() throws Exception {
37 | }
38 |
39 | public static boolean checkExists(String jobName, String jobGroup) throws SchedulerException {
40 | TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
41 | return scheduler.checkExists(triggerKey);
42 | }
43 |
44 | public static void addJob(String jobName, String jobGroup, String cronExpression, Map jobDataMap) throws SchedulerException {
45 | TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
46 | JobKey jobKey = new JobKey(jobName, jobGroup);
47 | if (!scheduler.checkExists(triggerKey)) {
48 | CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing();
49 | CronTrigger cronTrigger = (CronTrigger)TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();
50 | Class extends Job> jobClass_ = MyQuartzJobBean.class;
51 | JobDetail jobDetail = JobBuilder.newJob(jobClass_).withIdentity(jobKey).usingJobData(new JobDataMap(jobDataMap)).build();
52 | Date date = scheduler.scheduleJob(jobDetail, cronTrigger);
53 | logger.info("Quartz schedule job success -> jobName:{}, jobGroup:{}, cronExpression:{}", jobName, jobGroup, cronExpression);
54 | }
55 | }
56 |
57 | public static void removeJob(String jobName, String jobGroup) throws SchedulerException {
58 | JobKey jobKey = new JobKey(jobName, jobGroup);
59 | scheduler.deleteJob(jobKey);
60 | logger.info("Quartz delete job success -> jobName:{}, jobGroup:{}", jobName, jobGroup);
61 | }
62 |
63 | public static void updateJobCron(String jobName, String jobGroup, String cronExpression, Map jobDataMap) throws SchedulerException {
64 | TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
65 | if (scheduler.checkExists(triggerKey)) {
66 | CronTrigger oldTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
67 | String oldCron = oldTrigger.getCronExpression();
68 | if (!oldCron.equals(cronExpression)) {
69 | CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing();
70 | oldTrigger = (CronTrigger) oldTrigger.getTriggerBuilder().withIdentity(triggerKey).usingJobData(new JobDataMap(jobDataMap)).withSchedule(cronScheduleBuilder).build();
71 | scheduler.rescheduleJob(triggerKey, oldTrigger);
72 | logger.info("Quartz reschedule job success -> jobName:{}, jobGroup:{}, cronExpression:{}", jobName, jobGroup, cronExpression);
73 | }
74 | }
75 | }
76 |
77 | public static void clear() throws SchedulerException {
78 | scheduler.clear();
79 | }
80 |
81 | public static Set getTriggerKeys() throws SchedulerException {
82 | return scheduler.getTriggerKeys(GroupMatcher.anyTriggerGroup());
83 | }
84 |
85 | public static Set getTriggerKeysGroupEquals(String group) throws SchedulerException {
86 | return scheduler.getTriggerKeys(GroupMatcher.groupEquals(group));
87 | }
88 |
89 | public static Set getJobKeys() throws SchedulerException {
90 | return scheduler.getJobKeys(GroupMatcher.anyJobGroup());
91 | }
92 |
93 | public static Set getJobKeysGroupEquals(String group) throws SchedulerException {
94 | return scheduler.getJobKeys(GroupMatcher.groupEquals(group));
95 | }
96 |
97 | public static List getJobGroupNames() throws SchedulerException {
98 | return scheduler.getJobGroupNames();
99 | }
100 |
101 | public static List getTriggerGroupNames() throws SchedulerException {
102 | return scheduler.getTriggerGroupNames();
103 | }
104 |
105 | public static List getCurrentlyExecutingJobs() throws SchedulerException {
106 | return scheduler.getCurrentlyExecutingJobs();
107 | }
108 |
109 | }
110 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/scheduler/impl/quartz/MyDynamicSchedulerConfig.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.scheduler.impl.quartz;
2 |
3 | import org.quartz.Scheduler;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.Configuration;
7 | import org.springframework.core.io.ClassPathResource;
8 | import org.springframework.scheduling.quartz.SchedulerFactoryBean;
9 |
10 | /**
11 | * 动态调度器配置
12 | *
13 | * @author kpali
14 | */
15 | @Configuration
16 | public class MyDynamicSchedulerConfig {
17 |
18 | public MyDynamicSchedulerConfig() {
19 | }
20 |
21 | @Autowired
22 | MyJobFactory myJobFactory;
23 |
24 | @Bean
25 | public SchedulerFactoryBean getSchedulerFactoryBean() {
26 | SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean();
27 | schedulerFactory.setAutoStartup(true);
28 | schedulerFactory.setOverwriteExistingJobs(true);
29 | schedulerFactory.setApplicationContextSchedulerContextKey("applicationContext");
30 | schedulerFactory.setConfigLocation(new ClassPathResource("quartz.properties"));
31 | schedulerFactory.setJobFactory(myJobFactory);
32 | return schedulerFactory;
33 | }
34 |
35 | @Bean(
36 | initMethod = "start",
37 | destroyMethod = "destroy"
38 | )
39 | public MyDynamicScheduler getMyDynamicScheduler(SchedulerFactoryBean schedulerFactory) {
40 | Scheduler scheduler = schedulerFactory.getScheduler();
41 | MyDynamicScheduler myDynamicScheduler = new MyDynamicScheduler();
42 | myDynamicScheduler.setScheduler(scheduler);
43 | return myDynamicScheduler;
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/scheduler/impl/quartz/MyJobFactory.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.scheduler.impl.quartz;
2 |
3 | import org.quartz.spi.TriggerFiredBundle;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
6 | import org.springframework.scheduling.quartz.AdaptableJobFactory;
7 | import org.springframework.stereotype.Component;
8 |
9 | /**
10 | * 作业工厂类,主要为了实现Spring Bean注入到Job
11 | *
12 | * @author kpali
13 | */
14 | @Component
15 | public class MyJobFactory extends AdaptableJobFactory {
16 |
17 | @Autowired
18 | private AutowireCapableBeanFactory capableBeanFactory;
19 |
20 | @Override
21 | protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
22 | Object jobInstance = super.createJobInstance(bundle);
23 | capableBeanFactory.autowireBean(jobInstance);
24 | return jobInstance;
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/scheduler/impl/quartz/MyQuartzJobBean.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.scheduler.impl.quartz;
2 |
3 | import me.kpali.wolfflow.core.exception.TaskFlowTriggerException;
4 | import me.kpali.wolfflow.core.model.TaskFlowContextKey;
5 | import me.kpali.wolfflow.core.scheduler.ITaskFlowScheduler;
6 | import org.quartz.JobDataMap;
7 | import org.quartz.JobExecutionContext;
8 | import org.quartz.JobExecutionException;
9 | import org.quartz.JobKey;
10 | import org.springframework.beans.factory.annotation.Autowired;
11 | import org.springframework.scheduling.quartz.QuartzJobBean;
12 |
13 | /**
14 | * Quartz作业
15 | *
16 | * @author kpali
17 | */
18 | public class MyQuartzJobBean extends QuartzJobBean {
19 | public MyQuartzJobBean() {
20 | }
21 |
22 | @Autowired
23 | ITaskFlowScheduler taskFlowScheduler;
24 |
25 | @Override
26 | protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
27 | JobKey jobKey = context.getTrigger().getJobKey();
28 | Long taskFlowId = Long.valueOf(jobKey.getName());
29 | Long fromTaskId = null;
30 | Long toTaskId = null;
31 | JobDataMap jobDataMap = context.getMergedJobDataMap();
32 | if (jobDataMap != null) {
33 | fromTaskId = (jobDataMap.get(TaskFlowContextKey.FROM_TASK_ID) == null ? null : jobDataMap.getLong(TaskFlowContextKey.FROM_TASK_ID));
34 | toTaskId = (jobDataMap.get(TaskFlowContextKey.TO_TASK_ID) == null ? null : jobDataMap.getLong(TaskFlowContextKey.TO_TASK_ID));
35 | }
36 | try {
37 | if (fromTaskId != null && fromTaskId.equals(toTaskId)) {
38 | taskFlowScheduler.execute(taskFlowId, fromTaskId, null);
39 | } else if (fromTaskId != null) {
40 | taskFlowScheduler.executeFrom(taskFlowId, fromTaskId, null);
41 | } else if (toTaskId != null) {
42 | taskFlowScheduler.executeTo(taskFlowId, toTaskId, null);
43 | } else {
44 | taskFlowScheduler.execute(taskFlowId, null);
45 | }
46 | } catch (TaskFlowTriggerException e) {
47 | throw new JobExecutionException(e);
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/util/IdGenerator.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.util;
2 |
3 | import me.kpali.wolfflow.core.cluster.IClusterController;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.stereotype.Component;
6 |
7 | /**
8 | * ID生成器
9 | *
10 | * @author kpali
11 | */
12 | @Component
13 | public class IdGenerator {
14 | @Autowired
15 | private IClusterController clusterController;
16 |
17 | private SnowFlake snowFlake;
18 |
19 | public synchronized long nextId() {
20 | if (snowFlake == null) {
21 | snowFlake = new SnowFlake(this.clusterController.getNodeId());
22 | }
23 | return snowFlake.nextId();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/util/SnowFlake.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.util;
2 |
3 | /**
4 | * snowflake算法
5 | *
6 | * @author kpali
7 | */
8 | public class SnowFlake {
9 | /**
10 | * 起始的时间戳
11 | */
12 | private final static long START_STMP = 1480166465631L;
13 |
14 | /**
15 | * 每一部分占用的位数
16 | */
17 | private final static long SEQUENCE_BIT = 8; //序列号占用的位数
18 | private final static long MACHINE_BIT = 5; //机器标识占用的位数
19 |
20 | /**
21 | * 每一部分的最大值
22 | */
23 | private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);
24 | private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);
25 |
26 | /**
27 | * 每一部分向左的位移
28 | */
29 | private final static long MACHINE_LEFT = SEQUENCE_BIT;
30 | private final static long TIMESTMP_LEFT = MACHINE_LEFT + MACHINE_BIT;
31 |
32 | private long machineId; //机器标识
33 | private long sequence = 0L; //序列号
34 | private long lastStmp = -1L;//上一次时间戳
35 |
36 | public SnowFlake(long machineId) {
37 | if (machineId > MAX_MACHINE_NUM || machineId < 0) {
38 | throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0");
39 | }
40 | this.machineId = machineId;
41 | }
42 |
43 | /**
44 | * 产生下一个ID
45 | *
46 | * @return
47 | */
48 | public synchronized long nextId() {
49 | long currStmp = getNewstmp();
50 | if (currStmp < lastStmp) {
51 | throw new RuntimeException("Clock moved backwards. Refusing to generate id");
52 | }
53 |
54 | if (currStmp == lastStmp) {
55 | //相同毫秒内,序列号自增
56 | sequence = (sequence + 1) & MAX_SEQUENCE;
57 | //同一毫秒的序列数已经达到最大
58 | if (sequence == 0L) {
59 | currStmp = getNextMill();
60 | }
61 | } else {
62 | //不同毫秒内,序列号置为0
63 | sequence = 0L;
64 | }
65 |
66 | lastStmp = currStmp;
67 |
68 | return (currStmp - START_STMP) << TIMESTMP_LEFT //时间戳部分
69 | | machineId << MACHINE_LEFT //机器标识部分
70 | | sequence; //序列号部分
71 | }
72 |
73 | private long getNextMill() {
74 | long mill = getNewstmp();
75 | while (mill <= lastStmp) {
76 | mill = getNewstmp();
77 | }
78 | return mill;
79 | }
80 |
81 | private long getNewstmp() {
82 | return System.currentTimeMillis();
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/util/TaskFlowUtils.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.util;
2 |
3 | import me.kpali.wolfflow.core.model.Link;
4 | import me.kpali.wolfflow.core.model.Task;
5 | import me.kpali.wolfflow.core.model.TaskFlow;
6 |
7 | import java.util.*;
8 |
9 | /**
10 | * 任务流工具类
11 | *
12 | * @author kpali
13 | */
14 | public class TaskFlowUtils {
15 |
16 | /**
17 | * 拓扑排序算法
18 | *
19 | * @param taskFlow
20 | * @return
21 | */
22 | public static List topologicalSort(TaskFlow taskFlow) {
23 | List sortedTaskList = new ArrayList<>();
24 | int taskCount = taskFlow.getTaskList().size();
25 |
26 | Map id_mapto_task = new HashMap<>();
27 | for (Task task : taskFlow.getTaskList()) {
28 | id_mapto_task.put(task.getId(), task);
29 | }
30 |
31 | // 计算节点入度
32 | Map taskId_mapto_inDegree = new HashMap<>();
33 | for (Task task : taskFlow.getTaskList()) {
34 | int inDegree = 0;
35 | for (Link link : taskFlow.getLinkList()) {
36 | if (link.getTarget().equals(task.getId())) {
37 | inDegree++;
38 | }
39 | }
40 | taskId_mapto_inDegree.put(task.getId(), inDegree);
41 | }
42 |
43 | // 从入度为0的节点开始遍历,对遍历过的节点将其子节点的入度减1,重复此步骤,直到遍历完所有节点
44 | Deque deque = new ArrayDeque<>();
45 | for (Long taskId : taskId_mapto_inDegree.keySet()) {
46 | int inDegree = taskId_mapto_inDegree.get(taskId);
47 | if (inDegree == 0) {
48 | deque.offer(id_mapto_task.get(taskId));
49 | }
50 | }
51 | while (!deque.isEmpty()) {
52 | Task task = deque.poll();
53 | sortedTaskList.add(task);
54 |
55 | for (Link link : taskFlow.getLinkList()) {
56 | if (link.getSource().equals(task.getId())) {
57 | Long childTaskId = link.getTarget();
58 | int inDegree = taskId_mapto_inDegree.get(childTaskId);
59 | inDegree--;
60 | taskId_mapto_inDegree.put(childTaskId, inDegree);
61 | if (inDegree == 0) {
62 | deque.offer(id_mapto_task.get(childTaskId));
63 | }
64 | }
65 | }
66 | }
67 |
68 | // 如果无法遍历完所有节点,则说明当前拓扑不是有向无环图,不存在拓扑排序。
69 | return sortedTaskList.size() == taskCount ? sortedTaskList : null;
70 | }
71 |
72 | /**
73 | * 根据从指定任务开始或到指定任务结束,对任务流进行剪裁
74 | *
75 | * @param taskFlow
76 | * @param fromTaskId
77 | * @param toTaskId
78 | * @return
79 | */
80 | public static TaskFlow prune(TaskFlow taskFlow, Long fromTaskId, Long toTaskId) {
81 | TaskFlow prunedTaskFlow = new TaskFlow();
82 | prunedTaskFlow.setId(taskFlow.getId());
83 | prunedTaskFlow.setCron(taskFlow.getCron());
84 | prunedTaskFlow.setTaskList(new ArrayList<>());
85 | prunedTaskFlow.setLinkList(new ArrayList<>());
86 |
87 | Map id_mapto_task = new HashMap<>();
88 | for (Task task : taskFlow.getTaskList()) {
89 | id_mapto_task.put(task.getId(), task);
90 | }
91 | Deque deque = new ArrayDeque<>();
92 |
93 | if (fromTaskId == null && toTaskId == null) {
94 | // 所有任务
95 | prunedTaskFlow = taskFlow;
96 | } else if (fromTaskId != null && fromTaskId.equals(toTaskId)) {
97 | // 指定任务
98 | Task fromTask = id_mapto_task.get(fromTaskId);
99 | prunedTaskFlow.getTaskList().add(fromTask);
100 | } else if (fromTaskId != null) {
101 | // 从指定任务开始
102 | Task fromTask = id_mapto_task.get(fromTaskId);
103 | prunedTaskFlow.getTaskList().add(fromTask);
104 | deque.offer(fromTask);
105 | while (!deque.isEmpty()) {
106 | Task task = deque.poll();
107 | for (Link link : taskFlow.getLinkList()) {
108 | if (link.getSource().equals(task.getId())) {
109 | Task childTask = id_mapto_task.get(link.getTarget());
110 | if (!prunedTaskFlow.getTaskList().contains(childTask)) {
111 | prunedTaskFlow.getTaskList().add(childTask);
112 | }
113 | prunedTaskFlow.getLinkList().add(link);
114 | deque.offer(childTask);
115 | }
116 | }
117 | }
118 | } else {
119 | // 到指定任务结束
120 | Task toTask = id_mapto_task.get(toTaskId);
121 | prunedTaskFlow.getTaskList().add(toTask);
122 | deque.offer(toTask);
123 | while (!deque.isEmpty()) {
124 | Task task = deque.poll();
125 | for (Link link : taskFlow.getLinkList()) {
126 | if (link.getTarget().equals(task.getId())) {
127 | Task parentTask = id_mapto_task.get(link.getSource());
128 | if (!prunedTaskFlow.getTaskList().contains(parentTask)) {
129 | prunedTaskFlow.getTaskList().add(parentTask);
130 | }
131 | prunedTaskFlow.getLinkList().add(link);
132 | deque.offer(parentTask);
133 | }
134 | }
135 | }
136 | }
137 | return prunedTaskFlow;
138 | }
139 |
140 | }
141 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/util/context/ContextWrapper.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.util.context;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import java.util.concurrent.ConcurrentHashMap;
6 |
7 | /**
8 | * 上下文包装类
9 | *
10 | * @author kpali
11 | */
12 | public class ContextWrapper {
13 | public ContextWrapper() {
14 | this.context = new ConcurrentHashMap<>();
15 | }
16 |
17 | public ContextWrapper(ConcurrentHashMap context) {
18 | this.context = (context == null ? new ConcurrentHashMap<>() : context);
19 | }
20 |
21 | protected ConcurrentHashMap context;
22 |
23 | public ConcurrentHashMap getContext() {
24 | return context;
25 | }
26 |
27 | public void setContext(ConcurrentHashMap context) {
28 | this.context = context;
29 | }
30 |
31 | public Object get(String key) {
32 | return this.context.get(key);
33 | }
34 |
35 | public Object put(String key, Object value) {
36 | return this.context.put(key, value);
37 | }
38 |
39 | public boolean containsKey(String key) {
40 | return this.context.containsKey(key);
41 | }
42 |
43 | public T getValue(String key, Class clazz) {
44 | Object value = this.context.get(key);
45 | return this.cast(value, clazz);
46 | }
47 |
48 | public List getList(String key, Class clazz) {
49 | Object value = this.context.get(key);
50 | if (value != null) {
51 | List result = new ArrayList();
52 | if (value instanceof List>) {
53 | for (Object o : (List>) value) {
54 | result.add(this.cast(o, clazz));
55 | }
56 | return result;
57 | }
58 | }
59 | return null;
60 | }
61 |
62 | private T cast(Object obj, Class clazz) {
63 | if (obj != null) {
64 | if (!clazz.isInstance(obj) && obj instanceof Integer) {
65 | // Integer类型 转 Long类型
66 | Long longObj = ((Integer) obj).longValue();
67 | if (clazz.isInstance(longObj)) {
68 | return clazz.cast(longObj);
69 | }
70 | }
71 | return clazz.cast(obj);
72 | }
73 | return null;
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/util/context/DeliveryContextWrapper.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.util.context;
2 |
3 | import java.util.concurrent.ConcurrentHashMap;
4 |
5 | /**
6 | * 传递上下文包装类
7 | *
8 | * @author kpali
9 | */
10 | public class DeliveryContextWrapper extends ContextWrapper {
11 | public DeliveryContextWrapper() {
12 | super();
13 | }
14 |
15 | public DeliveryContextWrapper(ConcurrentHashMap context) {
16 | super(context);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/util/context/ParamsWrapper.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.util.context;
2 |
3 | import java.util.concurrent.ConcurrentHashMap;
4 |
5 | /**
6 | * 任务流上下文参数包装类
7 | *
8 | * @author kpali
9 | */
10 | public class ParamsWrapper extends ContextWrapper {
11 | public ParamsWrapper() {
12 | super();
13 | }
14 |
15 | public ParamsWrapper(ConcurrentHashMap context) {
16 | super(context);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/util/context/TaskContextWrapper.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.util.context;
2 |
3 | import java.util.concurrent.ConcurrentHashMap;
4 |
5 | /**
6 | * 任务上下文包装类
7 | *
8 | * @author kpali
9 | */
10 | public class TaskContextWrapper extends ContextWrapper {
11 | public TaskContextWrapper() {
12 | super();
13 | }
14 |
15 | public TaskContextWrapper(ConcurrentHashMap context) {
16 | super(context);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/java/me/kpali/wolfflow/core/util/context/TaskFlowContextWrapper.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.util.context;
2 |
3 | import me.kpali.wolfflow.core.model.TaskFlowContextKey;
4 |
5 | import java.util.Map;
6 | import java.util.concurrent.ConcurrentHashMap;
7 |
8 | /**
9 | * 任务流上下文包装类
10 | *
11 | * @author kpali
12 | */
13 | public class TaskFlowContextWrapper extends ContextWrapper {
14 | public TaskFlowContextWrapper() {
15 | super();
16 | }
17 |
18 | public TaskFlowContextWrapper(ConcurrentHashMap context) {
19 | super(context);
20 | }
21 |
22 | public ConcurrentHashMap getTaskFlowContext() {
23 | ConcurrentHashMap taskFlowContext = null;
24 | if (this.getContext() != null) {
25 | taskFlowContext = new ConcurrentHashMap<>();
26 | for (String key : this.getContext().keySet()) {
27 | if (TaskFlowContextKey.TASK_CONTEXTS.equals(key)) {
28 | continue;
29 | }
30 | taskFlowContext.put(key, this.getContext().get(key));
31 | }
32 | }
33 | return taskFlowContext;
34 | }
35 |
36 | public ConcurrentHashMap getParams() {
37 | Object paramsObj = this.context.get(TaskFlowContextKey.PARAMS);
38 | if (paramsObj == null) {
39 | return null;
40 | }
41 | return (ConcurrentHashMap) paramsObj;
42 | }
43 |
44 | public synchronized void setParams(ConcurrentHashMap params) {
45 | Object paramsObj = this.context.get(TaskFlowContextKey.PARAMS);
46 | if (paramsObj == null) {
47 | this.context.put(TaskFlowContextKey.PARAMS, params);
48 | } else {
49 | paramsObj = params;
50 | }
51 | }
52 |
53 | public Object getParam(String key) {
54 | ConcurrentHashMap params = this.getParams();
55 | if (params == null) {
56 | return null;
57 | }
58 | return params.get(key);
59 | }
60 |
61 | public synchronized void putParam(String key, Object value) {
62 | ConcurrentHashMap params = this.getParams();
63 | if (params == null) {
64 | params = new ConcurrentHashMap<>();
65 | this.context.put(TaskFlowContextKey.PARAMS, params);
66 | }
67 | params.put(key, value);
68 | }
69 |
70 | public ParamsWrapper getParamsWrapper() {
71 | ConcurrentHashMap params = this.getParams();
72 | if (params == null) {
73 | return null;
74 | }
75 | return new ParamsWrapper(params);
76 | }
77 |
78 | public ConcurrentHashMap getDeliveryContext() {
79 | Object deliveryContextObj = this.context.get(TaskFlowContextKey.DELIVERY_CONTEXT);
80 | if (deliveryContextObj == null) {
81 | return null;
82 | }
83 | return (ConcurrentHashMap) deliveryContextObj;
84 | }
85 |
86 | public synchronized void setDeliveryContext(ConcurrentHashMap deliveryContext) {
87 | Object deliveryContextObj = this.context.get(TaskFlowContextKey.DELIVERY_CONTEXT);
88 | if (deliveryContextObj == null) {
89 | this.context.put(TaskFlowContextKey.DELIVERY_CONTEXT, deliveryContext);
90 | } else {
91 | deliveryContextObj = deliveryContext;
92 | }
93 | }
94 |
95 | public Object getDeliveryContext(String key) {
96 | ConcurrentHashMap deliveryContext = this.getDeliveryContext();
97 | if (deliveryContext == null) {
98 | return null;
99 | }
100 | return deliveryContext.get(key);
101 | }
102 |
103 | public synchronized void putDeliveryContext(String key, Object value) {
104 | ConcurrentHashMap deliveryContext = this.getDeliveryContext();
105 | if (deliveryContext == null) {
106 | deliveryContext = new ConcurrentHashMap<>();
107 | this.context.put(TaskFlowContextKey.DELIVERY_CONTEXT, deliveryContext);
108 | }
109 | deliveryContext.put(key, value);
110 | }
111 |
112 | public DeliveryContextWrapper getDeliveryContextWrapper() {
113 | ConcurrentHashMap deliveryContext = this.getDeliveryContext();
114 | if (deliveryContext == null) {
115 | return null;
116 | }
117 | return new DeliveryContextWrapper(deliveryContext);
118 | }
119 |
120 | public Map> getTaskContexts() {
121 | Object taskContextObj = this.context.get(TaskFlowContextKey.TASK_CONTEXTS);
122 | if (taskContextObj == null) {
123 | return null;
124 | }
125 | return (Map>) taskContextObj;
126 | }
127 |
128 | public synchronized void setTaskContexts(Map> taskContexts) {
129 | Object taskContextObj = this.context.get(TaskFlowContextKey.TASK_CONTEXTS);
130 | if (taskContextObj == null) {
131 | this.context.put(TaskFlowContextKey.TASK_CONTEXTS, taskContexts);
132 | } else {
133 | taskContextObj = taskContexts;
134 | }
135 | }
136 |
137 | public TaskContextWrapper getTaskContextWrapper(String taskId) {
138 | Map> taskContexts = this.getTaskContexts();
139 | if (taskContexts == null) {
140 | return null;
141 | }
142 | ConcurrentHashMap taskContext = taskContexts.get(taskId);
143 | if (taskContext == null) {
144 | return null;
145 | }
146 | return new TaskContextWrapper(taskContext);
147 | }
148 |
149 | public ConcurrentHashMap getTaskContext(String taskId) {
150 | Map> taskContexts = this.getTaskContexts();
151 | if (taskContexts == null) {
152 | return null;
153 | }
154 | return taskContexts.get(taskId);
155 | }
156 |
157 | public synchronized void putTaskContext(String taskId, ConcurrentHashMap taskContext) {
158 | Map> taskContexts = this.getTaskContexts();
159 | if (taskContexts == null) {
160 | taskContexts = new ConcurrentHashMap<>();
161 | this.context.put(TaskFlowContextKey.TASK_CONTEXTS, taskContexts);
162 | }
163 | taskContexts.put(taskId, taskContext);
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/main/resources/quartz.properties:
--------------------------------------------------------------------------------
1 | org.quartz.scheduler.instanceName = MyScheduler
2 | org.quartz.threadPool.threadCount = 10
3 | org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
4 | org.quartz.jobStore.misfireThreshold = 60000
--------------------------------------------------------------------------------
/wolf-flow-core/src/test/java/me/kpali/wolfflow/core/BaseTest.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core;
2 |
3 | import me.kpali.wolfflow.core.config.ClusterConfig;
4 | import me.kpali.wolfflow.core.config.ExecutorConfig;
5 | import me.kpali.wolfflow.core.config.SchedulerConfig;
6 | import me.kpali.wolfflow.core.launcher.Launcher;
7 | import org.junit.jupiter.api.MethodOrderer;
8 | import org.junit.jupiter.api.Order;
9 | import org.junit.jupiter.api.Test;
10 | import org.junit.jupiter.api.TestMethodOrder;
11 | import org.springframework.beans.factory.annotation.Autowired;
12 | import org.springframework.boot.test.context.SpringBootTest;
13 |
14 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
15 | @SpringBootTest
16 | public class BaseTest {
17 | @Autowired
18 | ClusterConfig clusterConfig;
19 |
20 | @Autowired
21 | SchedulerConfig schedulerConfig;
22 |
23 | @Autowired
24 | ExecutorConfig executorConfig;
25 |
26 | @Autowired
27 | Launcher launcher;
28 |
29 | @Order(0)
30 | @Test
31 | public void init() {
32 | this.clusterConfig.setNodeHeartbeatInterval(30);
33 | this.clusterConfig.setNodeHeartbeatDuration(90);
34 | this.clusterConfig.setGenerateNodeIdLockLeaseTime(60);
35 | this.clusterConfig.setTaskFlowLogLockWaitTime(10);
36 | this.clusterConfig.setTaskFlowLogLockLeaseTime(15);
37 | this.clusterConfig.setTaskLogLockWaitTime(10);
38 | this.clusterConfig.setTaskLogLockLeaseTime(15);
39 |
40 | this.schedulerConfig.setExecRequestScanInterval(1);
41 | this.schedulerConfig.setCronScanInterval(10);
42 | this.schedulerConfig.setCronScanLockWaitTime(10);
43 | this.schedulerConfig.setCronScanLockLeaseTime(60);
44 | this.schedulerConfig.setCorePoolSize(10);
45 | this.schedulerConfig.setMaximumPoolSize(10);
46 |
47 | this.executorConfig.setCorePoolSize(30);
48 | this.executorConfig.setMaximumPoolSize(30);
49 |
50 | this.launcher.startup();
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/test/java/me/kpali/wolfflow/core/cluster/impl/DefaultClusterControllerTest.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.cluster.impl;
2 |
3 | import me.kpali.wolfflow.core.BaseTest;
4 | import me.kpali.wolfflow.core.cluster.IClusterController;
5 | import me.kpali.wolfflow.core.exception.GenerateNodeIdException;
6 | import me.kpali.wolfflow.core.model.ManualConfirmed;
7 | import me.kpali.wolfflow.core.model.TaskFlowExecRequest;
8 | import org.junit.jupiter.api.*;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 |
11 | import java.util.concurrent.TimeUnit;
12 |
13 | import static org.junit.jupiter.api.Assertions.*;
14 |
15 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
16 | public class DefaultClusterControllerTest extends BaseTest {
17 |
18 | @Autowired
19 | IClusterController clusterController;
20 |
21 | @Test
22 | public void testGetNodeId() throws GenerateNodeIdException {
23 | this.clusterController.generateNodeId();
24 | assertNotNull(this.clusterController.getNodeId());
25 | }
26 |
27 | @Order(1)
28 | @Test
29 | public void testHeartbeat() {
30 | this.clusterController.heartbeat();
31 | }
32 |
33 | @Order(2)
34 | @Test
35 | public void testIsNodeAlive() {
36 | assertTrue(this.clusterController.isNodeAlive(this.clusterController.getNodeId()));
37 | }
38 |
39 | @Test
40 | public void testLock() {
41 | this.clusterController.lock("testLock");
42 | }
43 |
44 | @Test
45 | public void testLockWithLeaseTime() {
46 | this.clusterController.lock("testLockWithLeaseTime", 15, TimeUnit.SECONDS);
47 | }
48 |
49 | @Test
50 | public void testTryLock() {
51 | this.clusterController.tryLock("testTryLock", 10, 15, TimeUnit.SECONDS);
52 | }
53 |
54 | @Test
55 | public void testUnlock() {
56 | String lockName = "testUnlock";
57 | this.clusterController.lock(lockName);
58 | this.clusterController.unlock(lockName);
59 | }
60 |
61 | @Test
62 | public void testExecRequest() {
63 | this.clusterController.execRequestOffer(new TaskFlowExecRequest());
64 | assertNotNull(this.clusterController.execRequestPoll());
65 | }
66 |
67 | @Test
68 | public void testStopRequest() {
69 | Long taskFlowLogId = 1L;
70 | this.clusterController.stopRequestAdd(taskFlowLogId);
71 | boolean isContains = this.clusterController.stopRequestContains(taskFlowLogId);
72 | assertEquals(isContains, true);
73 | this.clusterController.stopRequestRemove(taskFlowLogId);
74 | isContains = this.clusterController.stopRequestContains(taskFlowLogId);
75 | assertFalse(isContains);
76 | }
77 |
78 | @Test
79 | public void testManualConfirmed() {
80 | Long taskLogId = 1L;
81 | this.clusterController.manualConfirmedAdd(new ManualConfirmed(taskLogId, true, null));
82 | ManualConfirmed manualConfirmed = this.clusterController.manualConfirmedGet(taskLogId);
83 | assertNotNull(manualConfirmed);
84 | this.clusterController.manualConfirmedRemove(taskLogId);
85 | manualConfirmed = this.clusterController.manualConfirmedGet(taskLogId);
86 | assertNull(manualConfirmed);
87 | }
88 | }
--------------------------------------------------------------------------------
/wolf-flow-core/src/test/java/me/kpali/wolfflow/core/listener/TaskFlowEventListener.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.listener;
2 |
3 | import me.kpali.wolfflow.core.event.ScheduleStatusChangeEvent;
4 | import me.kpali.wolfflow.core.event.TaskFlowStatusChangeEvent;
5 | import me.kpali.wolfflow.core.event.TaskStatusChangeEvent;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 | import org.springframework.context.event.EventListener;
9 | import org.springframework.stereotype.Component;
10 |
11 | @Component
12 | public class TaskFlowEventListener {
13 | private static final Logger logger = LoggerFactory.getLogger(TaskFlowEventListener.class);
14 |
15 | @EventListener
16 | public void taskFlowScheduleStatusChange(ScheduleStatusChangeEvent event) {
17 | // 任务流调度状态变更监听,主要为定时任务流,状态有[加入调度、更新调度、调度失败]等
18 | }
19 |
20 | @EventListener
21 | public void taskFlowStatusChange(TaskFlowStatusChangeEvent event) {
22 | // 任务流状态变更监听,状态有[等待执行、执行中、执行成功、执行失败、停止中]等
23 | logger.info(">>>>>>>>>> Task flow [{}] status changed to: {}", event.getTaskFlowStatus().getTaskFlow().getId(), event.getTaskFlowStatus().getStatus());
24 | }
25 |
26 | @EventListener
27 | public void taskStatusChange(TaskStatusChangeEvent event) {
28 | // 任务状态变更监听,状态有[等待执行、执行中、执行成功、执行失败、停止中、跳过]等
29 | logger.info(">>>>>>>>>> Task [{}] status changed to: {}", event.getTaskStatus().getTask().getId(), event.getTaskStatus().getStatus());
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/test/java/me/kpali/wolfflow/core/model/AutoTask.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.model;
2 |
3 | import me.kpali.wolfflow.core.exception.TaskExecuteException;
4 | import me.kpali.wolfflow.core.exception.TaskInterruptedException;
5 | import me.kpali.wolfflow.core.exception.TaskRollbackException;
6 | import me.kpali.wolfflow.core.exception.TaskStopException;
7 | import me.kpali.wolfflow.core.logger.ITaskLogger;
8 | import me.kpali.wolfflow.core.util.SpringContextUtil;
9 | import me.kpali.wolfflow.core.util.context.TaskContextWrapper;
10 | import me.kpali.wolfflow.core.util.context.TaskFlowContextWrapper;
11 |
12 | import java.util.concurrent.ConcurrentHashMap;
13 |
14 | public class AutoTask extends Task {
15 | private boolean requiredToStop = false;
16 |
17 | @Override
18 | public void execute(ConcurrentHashMap context) throws TaskExecuteException, TaskInterruptedException {
19 | if (context == null) {
20 | throw new IllegalArgumentException();
21 | }
22 | try {
23 | ITaskLogger taskLogger = SpringContextUtil.getBean(ITaskLogger.class);
24 | TaskFlowContextWrapper taskFlowContextWrapper = new TaskFlowContextWrapper(context);
25 | ConcurrentHashMap taskContext = taskFlowContextWrapper.getTaskContext(this.getId().toString());
26 | TaskContextWrapper taskContextWrapper = new TaskContextWrapper(taskContext);
27 | Long taskLogId = taskContextWrapper.getValue(TaskContextKey.TASK_LOG_ID, Long.class);
28 | String taskLogFileId = taskContextWrapper.getValue(TaskContextKey.TASK_LOG_FILE_ID, String.class);
29 | taskLogger.log(taskLogFileId, "Task executing...", false);
30 | taskLogger.log(taskLogFileId, "Second line...\rThird line...\nFourth line...\r\nFifth line...", false);
31 | if (requiredToStop) {
32 | taskLogger.log(taskLogFileId, "Task execution is terminated", true);
33 | throw new TaskInterruptedException("Task execution is terminated");
34 | }
35 | taskLogger.log(taskLogFileId, "Task execution finished", true);
36 | } catch (TaskInterruptedException e) {
37 | throw e;
38 | } catch (Exception e) {
39 | throw new TaskExecuteException(e);
40 | }
41 | }
42 |
43 | @Override
44 | public void rollback(ConcurrentHashMap context) throws TaskRollbackException, TaskInterruptedException {
45 | try {
46 | ITaskLogger taskLogger = SpringContextUtil.getBean(ITaskLogger.class);
47 | TaskFlowContextWrapper taskFlowContextWrapper = new TaskFlowContextWrapper(context);
48 | ConcurrentHashMap taskContext = taskFlowContextWrapper.getTaskContext(this.getId().toString());
49 | TaskContextWrapper taskContextWrapper = new TaskContextWrapper(taskContext);
50 | Long taskLogId = taskContextWrapper.getValue(TaskContextKey.TASK_LOG_ID, Long.class);
51 | String taskLogFileId = taskContextWrapper.getValue(TaskContextKey.TASK_LOG_FILE_ID, String.class);
52 | taskLogger.log(taskLogFileId, "Task rolling back...", false);
53 | taskLogger.log(taskLogFileId, "Second line...\rThird line...\nFourth line...\r\nFifth line...", false);
54 | if (requiredToStop) {
55 | taskLogger.log(taskLogFileId, "Task execution is terminated", true);
56 | throw new TaskInterruptedException("Task execution is terminated");
57 | }
58 | taskLogger.log(taskLogFileId, "Task rollback finished", true);
59 | } catch (TaskInterruptedException e) {
60 | throw e;
61 | } catch (Exception e) {
62 | throw new TaskRollbackException(e);
63 | }
64 | }
65 |
66 | @Override
67 | public void stop(ConcurrentHashMap context) throws TaskStopException {
68 | this.requiredToStop = true;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/test/java/me/kpali/wolfflow/core/model/ManualTask.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.model;
2 |
3 | import me.kpali.wolfflow.core.cluster.IClusterController;
4 | import me.kpali.wolfflow.core.exception.TaskExecuteException;
5 | import me.kpali.wolfflow.core.exception.TaskInterruptedException;
6 | import me.kpali.wolfflow.core.exception.TaskRollbackException;
7 | import me.kpali.wolfflow.core.exception.TaskStopException;
8 | import me.kpali.wolfflow.core.util.SpringContextUtil;
9 | import me.kpali.wolfflow.core.util.context.TaskContextWrapper;
10 | import me.kpali.wolfflow.core.util.context.TaskFlowContextWrapper;
11 |
12 | import java.util.concurrent.ConcurrentHashMap;
13 |
14 | public class ManualTask extends Task {
15 | public ManualTask() {
16 | this.setManual(true);
17 | }
18 |
19 | private boolean requiredToStop = false;
20 |
21 | @Override
22 | public void execute(ConcurrentHashMap context) throws TaskExecuteException, TaskInterruptedException {
23 | try {
24 | IClusterController clusterController = SpringContextUtil.getBean(IClusterController.class);
25 | TaskFlowContextWrapper taskFlowContextWrapper = new TaskFlowContextWrapper(context);
26 | ConcurrentHashMap taskContext = taskFlowContextWrapper.getTaskContext(this.getId().toString());
27 | TaskContextWrapper taskContextWrapper = new TaskContextWrapper(taskContext);
28 | Long taskLogId = taskContextWrapper.getValue(TaskContextKey.TASK_LOG_ID, Long.class);
29 |
30 | while (true) {
31 | try {
32 | Thread.sleep(10);
33 | } catch (InterruptedException e) {
34 | Thread.currentThread().interrupt();
35 | }
36 | // 检查是否收到停止任务指令
37 | if (requiredToStop) {
38 | throw new TaskInterruptedException("Task execution is terminated");
39 | }
40 | // 检查手工确认结果
41 | ManualConfirmed manualConfirmed = clusterController.manualConfirmedGet(taskLogId);
42 | if (manualConfirmed != null) {
43 | clusterController.manualConfirmedRemove(taskLogId);
44 | if (manualConfirmed.getSuccess()) {
45 | break;
46 | } else {
47 | throw new TaskExecuteException(manualConfirmed.getMessage());
48 | }
49 | }
50 | }
51 | } catch (TaskInterruptedException e) {
52 | throw e;
53 | } catch (Exception e) {
54 | throw new TaskExecuteException(e);
55 | }
56 | }
57 |
58 | @Override
59 | public void rollback(ConcurrentHashMap context) throws TaskRollbackException, TaskInterruptedException {
60 | try {
61 | IClusterController clusterController = SpringContextUtil.getBean(IClusterController.class);
62 | TaskFlowContextWrapper taskFlowContextWrapper = new TaskFlowContextWrapper(context);
63 | ConcurrentHashMap taskContext = taskFlowContextWrapper.getTaskContext(this.getId().toString());
64 | TaskContextWrapper taskContextWrapper = new TaskContextWrapper(taskContext);
65 | Long taskLogId = taskContextWrapper.getValue(TaskContextKey.TASK_LOG_ID, Long.class);
66 |
67 | while (true) {
68 | try {
69 | Thread.sleep(10);
70 | } catch (InterruptedException e) {
71 | Thread.currentThread().interrupt();
72 | }
73 | // 检查是否收到停止任务指令
74 | if (requiredToStop) {
75 | throw new TaskInterruptedException("Task rollback is terminated");
76 | }
77 | // 检查手工确认结果
78 | ManualConfirmed manualConfirmed = clusterController.manualConfirmedGet(taskLogId);
79 | if (manualConfirmed != null) {
80 | clusterController.manualConfirmedRemove(taskLogId);
81 | if (manualConfirmed.getSuccess()) {
82 | break;
83 | } else {
84 | throw new TaskRollbackException(manualConfirmed.getMessage());
85 | }
86 | }
87 | }
88 | } catch (TaskInterruptedException e) {
89 | throw e;
90 | } catch (Exception e) {
91 | throw new TaskRollbackException(e);
92 | }
93 | }
94 |
95 | @Override
96 | public void stop(ConcurrentHashMap context) throws TaskStopException {
97 | this.requiredToStop = true;
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/wolf-flow-core/src/test/java/me/kpali/wolfflow/core/util/SpringContextUtil.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.core.util;
2 |
3 | import org.springframework.beans.BeansException;
4 | import org.springframework.context.ApplicationContext;
5 | import org.springframework.context.ApplicationContextAware;
6 | import org.springframework.stereotype.Component;
7 |
8 | @Component
9 | public class SpringContextUtil implements ApplicationContextAware {
10 | private static ApplicationContext applicationContext = null;
11 |
12 | @Override
13 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
14 | SpringContextUtil.applicationContext = applicationContext;
15 | }
16 |
17 | public static ApplicationContext getApplicationContext() {
18 | return applicationContext;
19 | }
20 |
21 | public static Object getBean(String beanId) {
22 | return applicationContext.getBean(beanId);
23 | }
24 |
25 | public static T getBean(Class requiredType) {
26 | return applicationContext.getBean(requiredType);
27 | }
28 | }
29 |
30 |
--------------------------------------------------------------------------------
/wolf-flow-sample-cluster/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 2.2.4.RELEASE
9 |
10 |
11 | me.kpali
12 | wolf-flow-sample-cluster
13 | 1.0.0
14 | wolf-flow-sample-cluster ${project.version}
15 | Wolf flow Sample Cluster
16 |
17 |
18 |
19 | org.springframework.boot
20 | spring-boot-starter
21 |
22 |
23 | org.springframework.boot
24 | spring-boot-starter-web
25 |
26 |
27 |
28 | org.springframework.boot
29 | spring-boot-devtools
30 | runtime
31 | true
32 |
33 |
34 | org.springframework.boot
35 | spring-boot-starter-test
36 | test
37 |
38 |
39 | org.junit.vintage
40 | junit-vintage-engine
41 |
42 |
43 |
44 |
45 |
46 | org.redisson
47 | redisson-spring-data-22
48 | 3.12.0
49 |
50 |
51 | org.redisson
52 | redisson-spring-boot-starter
53 | 3.12.0
54 |
55 |
56 |
57 | me.kpali
58 | wolf-flow-spring-boot-starter
59 | 2.1.1
60 |
61 |
62 |
63 |
64 |
65 |
66 | org.springframework.boot
67 | spring-boot-maven-plugin
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/wolf-flow-sample-cluster/src/main/java/me/kpali/wolfflow/sample/cluster/WolfFlowSampleClusterApplication.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.sample.cluster;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class WolfFlowSampleClusterApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(WolfFlowSampleClusterApplication.class, args);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/wolf-flow-sample-cluster/src/main/java/me/kpali/wolfflow/sample/cluster/config/RedissonSpringDataConfig.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.sample.cluster.config;
2 |
3 | import org.redisson.Redisson;
4 | import org.redisson.api.RedissonClient;
5 | import org.redisson.config.Config;
6 | import org.redisson.spring.data.connection.RedissonConnectionFactory;
7 | import org.springframework.beans.factory.annotation.Value;
8 | import org.springframework.context.annotation.Bean;
9 | import org.springframework.context.annotation.Configuration;
10 | import org.springframework.core.io.Resource;
11 |
12 | import java.io.IOException;
13 |
14 | @Configuration
15 | public class RedissonSpringDataConfig {
16 | @Bean
17 | public RedissonConnectionFactory redissonConnectionFactory(RedissonClient redisson) {
18 | return new RedissonConnectionFactory(redisson);
19 | }
20 |
21 | @Bean(destroyMethod = "shutdown")
22 | public RedissonClient redisson(@Value("classpath:/redisson.yaml") Resource configFile) throws IOException {
23 | Config config = Config.fromYAML(configFile.getInputStream());
24 | return Redisson.create(config);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/wolf-flow-sample-cluster/src/main/java/me/kpali/wolfflow/sample/cluster/controller/MetricsController.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.sample.cluster.controller;
2 |
3 | import me.kpali.wolfflow.core.monitor.IMonitor;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.web.bind.annotation.GetMapping;
6 | import org.springframework.web.bind.annotation.RestController;
7 |
8 | @RestController
9 | public class MetricsController {
10 | @Autowired
11 | IMonitor monitor;
12 |
13 | @GetMapping(value = "/prometheus", produces = {"text/plain; version=0.0.4; charset=utf-8"})
14 | public String getMetrics() {
15 | String response = monitor.scrape();
16 | return response;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/wolf-flow-sample-cluster/src/main/java/me/kpali/wolfflow/sample/cluster/controller/TriggerController.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.sample.cluster.controller;
2 |
3 | import me.kpali.wolfflow.core.exception.TaskFlowTriggerException;
4 | import me.kpali.wolfflow.core.scheduler.ITaskFlowScheduler;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.web.bind.annotation.GetMapping;
7 | import org.springframework.web.bind.annotation.PathVariable;
8 | import org.springframework.web.bind.annotation.RestController;
9 |
10 | @RestController
11 | public class TriggerController {
12 | @Autowired
13 | ITaskFlowScheduler taskFlowScheduler;
14 |
15 | @GetMapping(value = "/trigger/{taskFlowId}")
16 | public void trigger(@PathVariable Long taskFlowId) throws TaskFlowTriggerException {
17 | taskFlowScheduler.execute(taskFlowId, null);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/wolf-flow-sample-cluster/src/main/java/me/kpali/wolfflow/sample/cluster/listener/ApplicationReadyEventListener.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.sample.cluster.listener;
2 |
3 | import me.kpali.wolfflow.core.launcher.Launcher;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.boot.context.event.ApplicationReadyEvent;
6 | import org.springframework.context.ApplicationListener;
7 | import org.springframework.stereotype.Component;
8 |
9 | /**
10 | * 程序启动完成事件监听,在程序启动后启动任务流相关的后台线程
11 | * (必要)
12 | *
13 | * @author kpali
14 | */
15 | @Component
16 | public class ApplicationReadyEventListener implements ApplicationListener {
17 | @Autowired
18 | private Launcher launcher;
19 |
20 | @Override
21 | public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
22 | this.launcher.startup();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/wolf-flow-sample-cluster/src/main/java/me/kpali/wolfflow/sample/cluster/listener/TaskFlowEventListener.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.sample.cluster.listener;
2 |
3 | import me.kpali.wolfflow.core.event.ScheduleStatusChangeEvent;
4 | import me.kpali.wolfflow.core.event.TaskFlowStatusChangeEvent;
5 | import me.kpali.wolfflow.core.event.TaskStatusChangeEvent;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 | import org.springframework.context.event.EventListener;
9 | import org.springframework.stereotype.Component;
10 |
11 | /**
12 | * 任务流事件监听
13 | * (可选)
14 | *
15 | * @author kpali
16 | */
17 | @Component
18 | public class TaskFlowEventListener {
19 | private static final Logger logger = LoggerFactory.getLogger(TaskFlowEventListener.class);
20 |
21 | @EventListener
22 | public void taskFlowScheduleStatusChange(ScheduleStatusChangeEvent event) {
23 | // 任务流调度状态变更监听,主要为定时任务流,状态有[加入调度、更新调度、调度失败]等
24 | }
25 |
26 | @EventListener
27 | public void taskFlowStatusChange(TaskFlowStatusChangeEvent event) {
28 | // 任务流状态变更监听,状态有[等待执行、执行中、执行成功、执行失败、停止中]等
29 | logger.info(">>>>>>>>>> Task flow [{}] status changed to: {}", event.getTaskFlowStatus().getTaskFlow().getId(), event.getTaskFlowStatus().getStatus());
30 | }
31 |
32 | @EventListener
33 | public void taskStatusChange(TaskStatusChangeEvent event) {
34 | // 任务状态变更监听,状态有[等待执行、执行中、执行成功、执行失败、停止中、跳过]等
35 | logger.info(">>>>>>>>>> Task [{}] status changed to: {}", event.getTaskStatus().getTask().getId(), event.getTaskStatus().getStatus());
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/wolf-flow-sample-cluster/src/main/java/me/kpali/wolfflow/sample/cluster/taskflow/MyClusterController.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.sample.cluster.taskflow;
2 |
3 | import me.kpali.wolfflow.core.cluster.impl.DefaultClusterController;
4 | import me.kpali.wolfflow.core.config.ClusterConfig;
5 | import me.kpali.wolfflow.core.exception.GenerateNodeIdException;
6 | import me.kpali.wolfflow.core.model.ClusterConstants;
7 | import me.kpali.wolfflow.core.model.ManualConfirmed;
8 | import me.kpali.wolfflow.core.model.TaskFlowExecRequest;
9 | import org.redisson.api.*;
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 | import org.springframework.beans.factory.annotation.Autowired;
13 | import org.springframework.context.annotation.Primary;
14 | import org.springframework.stereotype.Component;
15 |
16 | import java.util.concurrent.TimeUnit;
17 |
18 | /**
19 | * 可以覆写默认集群控制器的方法实现自定义,本示例使用Redis实现集群控制器来支持集群
20 | * (可选)
21 | *
22 | * @author kpali
23 | */
24 | @Primary
25 | @Component
26 | public class MyClusterController extends DefaultClusterController {
27 | private static final Logger logger = LoggerFactory.getLogger(MyClusterController.class);
28 |
29 | @Autowired
30 | private RedissonClient redisson;
31 |
32 | @Autowired
33 | private ClusterConfig clusterConfig;
34 |
35 | private static final String NODE_ID = "nodeId";
36 | private static final String NODE_HEARTBEAT = "nodeHeartbeat";
37 | private static final String TASK_FLOW_EXEC_REQUEST = "taskFlowExecRequest";
38 | private static final String TASK_FLOW_STOP_REQUEST = "taskFlowStopRequest";
39 | private static final String MANUAL_CONFIRMED = "manualConfirmed";
40 |
41 | @Override
42 | public void generateNodeId() throws GenerateNodeIdException {
43 | try {
44 | this.lock(ClusterConstants.GENERATE_NODE_ID_LOCK,
45 | clusterConfig.getGenerateNodeIdLockLeaseTime(), TimeUnit.SECONDS);
46 | RAtomicLong atomicLong = redisson.getAtomicLong(NODE_ID);
47 | // 当前分布式ID生成算法默认最大支持32个节点
48 | int maxNodeNum = 32;
49 | for (int i = 0; i < maxNodeNum; i++) {
50 | long id = atomicLong.incrementAndGet() % maxNodeNum;
51 | if (!this.isNodeAlive(id)) {
52 | // ID没有被占用
53 | this.nodeId = id;
54 | return;
55 | }
56 | }
57 | throw new GenerateNodeIdException("Failed to generate node id, maximum node numbers has been reached!");
58 | } finally {
59 | try {
60 | this.unlock(ClusterConstants.GENERATE_NODE_ID_LOCK);
61 | } catch (Exception e) {
62 | logger.warn(e.getMessage(), e);
63 | }
64 | }
65 | }
66 |
67 | @Override
68 | public void heartbeat() {
69 | RLock lock = redisson.getLock(NODE_HEARTBEAT + ":" + this.getNodeId());
70 | lock.lock(this.clusterConfig.getNodeHeartbeatDuration(), TimeUnit.SECONDS);
71 | }
72 |
73 | @Override
74 | public boolean isNodeAlive(Long nodeId) {
75 | RLock lock = redisson.getLock(NODE_HEARTBEAT + ":" + nodeId);
76 | return lock.isLocked();
77 | }
78 |
79 | @Override
80 | public void lock(String name) {
81 | RLock lock = redisson.getLock(name);
82 | lock.lock();
83 | }
84 |
85 | @Override
86 | public void lock(String name, long leaseTime, TimeUnit unit) {
87 | RLock lock = redisson.getLock(name);
88 | lock.lock(leaseTime, unit);
89 | }
90 |
91 | @Override
92 | public boolean tryLock(String name, long waitTime, long leaseTime, TimeUnit unit) {
93 | RLock lock = redisson.getLock(name);
94 | boolean res = false;
95 | try {
96 | res = lock.tryLock(waitTime, leaseTime, unit);
97 | } catch (Exception e) {
98 | logger.error("Try lock [" + name + "] failed: " + e.getMessage(), e);
99 | }
100 | return res;
101 | }
102 |
103 | @Override
104 | public void unlock(String name) {
105 | RLock lock = redisson.getLock(name);
106 | lock.unlock();
107 | }
108 |
109 | @Override
110 | public boolean execRequestOffer(TaskFlowExecRequest request) {
111 | RQueue queue = redisson.getQueue(TASK_FLOW_EXEC_REQUEST);
112 | return queue.offer(request);
113 | }
114 |
115 | @Override
116 | public TaskFlowExecRequest execRequestPoll() {
117 | RQueue queue = redisson.getQueue(TASK_FLOW_EXEC_REQUEST);
118 | return queue.poll();
119 | }
120 |
121 | @Override
122 | public void stopRequestAdd(Long taskFlowLogId) {
123 | RSet set = redisson.getSet(TASK_FLOW_STOP_REQUEST);
124 | set.add(taskFlowLogId);
125 | }
126 |
127 | @Override
128 | public Boolean stopRequestContains(Long taskFlowLogId) {
129 | RSet set = redisson.getSet(TASK_FLOW_STOP_REQUEST);
130 | return set.contains(taskFlowLogId);
131 | }
132 |
133 | @Override
134 | public void stopRequestRemove(Long taskFlowLogId) {
135 | RSet set = redisson.getSet(TASK_FLOW_STOP_REQUEST);
136 | set.remove(taskFlowLogId);
137 | }
138 |
139 | @Override
140 | public void manualConfirmedAdd(ManualConfirmed manualConfirmed) {
141 | RMap map = redisson.getMap(MANUAL_CONFIRMED);
142 | map.put(manualConfirmed.getTaskLogId(), manualConfirmed);
143 | }
144 |
145 | @Override
146 | public ManualConfirmed manualConfirmedGet(Long taskLogId) {
147 | RMap map = redisson.getMap(MANUAL_CONFIRMED);
148 | return map.get(taskLogId);
149 | }
150 |
151 | @Override
152 | public void manualConfirmedRemove(Long taskLogId) {
153 | RMap map = redisson.getMap(MANUAL_CONFIRMED);
154 | map.remove(taskLogId);
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/wolf-flow-sample-cluster/src/main/java/me/kpali/wolfflow/sample/cluster/taskflow/MyTask.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.sample.cluster.taskflow;
2 |
3 | import me.kpali.wolfflow.core.exception.TaskExecuteException;
4 | import me.kpali.wolfflow.core.exception.TaskInterruptedException;
5 | import me.kpali.wolfflow.core.exception.TaskStopException;
6 | import me.kpali.wolfflow.core.logger.ITaskLogger;
7 | import me.kpali.wolfflow.core.model.Task;
8 | import me.kpali.wolfflow.core.model.TaskContextKey;
9 | import me.kpali.wolfflow.core.util.context.TaskContextWrapper;
10 | import me.kpali.wolfflow.core.util.context.TaskFlowContextWrapper;
11 | import me.kpali.wolfflow.sample.cluster.util.SpringContextUtil;
12 |
13 | import java.util.concurrent.ConcurrentHashMap;
14 |
15 | /**
16 | * 自定义任务,覆写父类的方法,实现自定义任务的执行内容
17 | * (必要)
18 | *
19 | * @author kpali
20 | */
21 | public class MyTask extends Task {
22 | private boolean requiredToStop = false;
23 |
24 | @Override
25 | public void execute(ConcurrentHashMap context) throws TaskExecuteException, TaskInterruptedException {
26 | try {
27 | ITaskLogger taskLogger = SpringContextUtil.getBean(ITaskLogger.class);
28 | TaskFlowContextWrapper taskFlowContextWrapper = new TaskFlowContextWrapper(context);
29 | ConcurrentHashMap taskContext = taskFlowContextWrapper.getTaskContext(this.getId().toString());
30 | TaskContextWrapper taskContextWrapper = new TaskContextWrapper(taskContext);
31 | Long taskLogId = taskContextWrapper.getValue(TaskContextKey.TASK_LOG_ID, Long.class);
32 | String taskLogFileId = taskContextWrapper.getValue(TaskContextKey.TASK_LOG_FILE_ID, String.class);
33 | taskLogger.log(taskLogFileId, "Task executing...", false);
34 | taskLogger.log(taskLogFileId, "Second line...\rThird line...\nFourth line...\r\nFifth line...", false);
35 | if (requiredToStop) {
36 | taskLogger.log(taskLogFileId, "Task execution is terminated", true);
37 | throw new TaskInterruptedException("Task execution is terminated");
38 | }
39 | taskLogger.log(taskLogFileId, "Task execution finished", true);
40 | } catch (TaskInterruptedException e) {
41 | throw e;
42 | } catch (Exception e) {
43 | throw new TaskExecuteException(e);
44 | }
45 | }
46 |
47 | @Override
48 | public void stop(ConcurrentHashMap context) throws TaskStopException {
49 | this.requiredToStop = true;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/wolf-flow-sample-cluster/src/main/java/me/kpali/wolfflow/sample/cluster/taskflow/MyTaskFlowExecutor.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.sample.cluster.taskflow;
2 |
3 | import me.kpali.wolfflow.core.executor.impl.DefaultTaskFlowExecutor;
4 | import org.springframework.context.annotation.Primary;
5 | import org.springframework.stereotype.Component;
6 |
7 | /**
8 | * 可以覆写默认任务流执行器的方法实现自定义,但一般情况下直接使用默认任务流执行器即可
9 | * (可选)
10 | *
11 | * @author kpali
12 | */
13 | @Primary
14 | @Component
15 | public class MyTaskFlowExecutor extends DefaultTaskFlowExecutor {
16 | }
17 |
--------------------------------------------------------------------------------
/wolf-flow-sample-cluster/src/main/java/me/kpali/wolfflow/sample/cluster/taskflow/MyTaskFlowLogger.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.sample.cluster.taskflow;
2 |
3 | import me.kpali.wolfflow.core.logger.impl.DefaultTaskFlowLogger;
4 | import org.springframework.context.annotation.Primary;
5 | import org.springframework.stereotype.Component;
6 |
7 | /**
8 | * 可以覆写默认任务流日志器的方法实现自定义,推荐使用数据库DAO实现日志持久化到硬盘。本示例为简单起见仍然使用默认实现存储到内存
9 | * (可选)
10 | *
11 | * @author kpali
12 | */
13 | @Primary
14 | @Component
15 | public class MyTaskFlowLogger extends DefaultTaskFlowLogger {
16 | }
17 |
--------------------------------------------------------------------------------
/wolf-flow-sample-cluster/src/main/java/me/kpali/wolfflow/sample/cluster/taskflow/MyTaskFlowQuerier.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.sample.cluster.taskflow;
2 |
3 | import me.kpali.wolfflow.core.exception.TaskFlowQueryException;
4 | import me.kpali.wolfflow.core.model.Link;
5 | import me.kpali.wolfflow.core.model.TaskFlow;
6 | import me.kpali.wolfflow.core.querier.impl.DefaultTaskFlowQuerier;
7 | import org.springframework.context.annotation.Primary;
8 | import org.springframework.stereotype.Component;
9 |
10 | import java.util.ArrayList;
11 | import java.util.List;
12 | import java.util.stream.Collectors;
13 |
14 | /**
15 | * 自定义任务流查询器,覆写父类的方法,实现自定义任务流查询器
16 | * (必要)
17 | *
18 | * @author kpali
19 | */
20 | @Primary
21 | @Component
22 | public class MyTaskFlowQuerier extends DefaultTaskFlowQuerier {
23 | @Override
24 | public TaskFlow getTaskFlow(Long taskFlowId) throws TaskFlowQueryException {
25 | List taskFlowList = this.listTaskFlow();
26 | return taskFlowList.stream().filter(taskFlow -> {
27 | return taskFlow.getId().equals(taskFlowId);
28 | }).findFirst().get();
29 | }
30 |
31 | @Override
32 | public List listCronTaskFlow() throws TaskFlowQueryException {
33 | List taskFlowList = this.listTaskFlow();
34 | return taskFlowList.stream().filter(taskFlow -> {
35 | return (taskFlow.getCron() != null && !taskFlow.getCron().trim().isEmpty());
36 | }).collect(Collectors.toList());
37 | }
38 |
39 | private List listTaskFlow() {
40 | /**
41 | * 示例拓扑图:
42 | * --> 9
43 | * 1 --> 2 --> 4 | ^
44 | * \ \ ^ | |
45 | * \ v / / --> 8
46 | * --> 3 --> 5 --> 6
47 | * \ |
48 | * \ v
49 | * --> 7
50 | * 10 --> 11
51 | */
52 |
53 | List taskFlowList = new ArrayList<>();
54 |
55 | TaskFlow taskFlow = new TaskFlow();
56 | taskFlow.setId(100L);
57 | taskFlow.setTaskList(new ArrayList<>());
58 | taskFlow.setLinkList(new ArrayList<>());
59 |
60 | MyTask myTask1 = new MyTask();
61 | myTask1.setId(1L);
62 | MyTask myTask2 = new MyTask();
63 | myTask2.setId(2L);
64 | MyTask myTask3 = new MyTask();
65 | myTask3.setId(3L);
66 | MyTask myTask4 = new MyTask();
67 | myTask4.setId(4L);
68 | MyTask myTask5 = new MyTask();
69 | myTask5.setId(5L);
70 | MyTask myTask6 = new MyTask();
71 | myTask6.setId(6L);
72 | MyTask myTask7 = new MyTask();
73 | myTask7.setId(7L);
74 | MyTask myTask8 = new MyTask();
75 | myTask8.setId(8L);
76 | MyTask myTask9 = new MyTask();
77 | myTask9.setId(9L);
78 | MyTask myTask10 = new MyTask();
79 | myTask10.setId(10L);
80 | MyTask myTask11 = new MyTask();
81 | myTask11.setId(11L);
82 | taskFlow.getTaskList().add(myTask3);
83 | taskFlow.getTaskList().add(myTask5);
84 | taskFlow.getTaskList().add(myTask1);
85 | taskFlow.getTaskList().add(myTask10);
86 | taskFlow.getTaskList().add(myTask9);
87 | taskFlow.getTaskList().add(myTask6);
88 | taskFlow.getTaskList().add(myTask4);
89 | taskFlow.getTaskList().add(myTask2);
90 | taskFlow.getTaskList().add(myTask7);
91 | taskFlow.getTaskList().add(myTask11);
92 | taskFlow.getTaskList().add(myTask8);
93 |
94 | taskFlow.getLinkList().add(new Link(1L, 2L));
95 | taskFlow.getLinkList().add(new Link(1L, 3L));
96 | taskFlow.getLinkList().add(new Link(2L, 3L));
97 | taskFlow.getLinkList().add(new Link(2L, 4L));
98 | taskFlow.getLinkList().add(new Link(3L, 4L));
99 | taskFlow.getLinkList().add(new Link(3L, 5L));
100 | taskFlow.getLinkList().add(new Link(5L, 6L));
101 | taskFlow.getLinkList().add(new Link(5L, 7L));
102 | taskFlow.getLinkList().add(new Link(6L, 7L));
103 | taskFlow.getLinkList().add(new Link(5L, 8L));
104 | taskFlow.getLinkList().add(new Link(5L, 9L));
105 | taskFlow.getLinkList().add(new Link(8L, 9L));
106 | taskFlow.getLinkList().add(new Link(10L, 11L));
107 |
108 | //taskFlow.setCron("0 * * * * ?");
109 | //taskFlow.setFromTaskId(1L);
110 |
111 | taskFlowList.add(taskFlow);
112 |
113 | return taskFlowList;
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/wolf-flow-sample-cluster/src/main/java/me/kpali/wolfflow/sample/cluster/taskflow/MyTaskFlowScheduler.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.sample.cluster.taskflow;
2 |
3 | import me.kpali.wolfflow.core.scheduler.impl.DefaultTaskFlowScheduler;
4 | import org.springframework.context.annotation.Primary;
5 | import org.springframework.stereotype.Component;
6 |
7 | /**
8 | * 可以覆写默认任务流调度器的方法实现自定义,但一般情况下直接使用默认任务流调度器即可
9 | * (可选)
10 | *
11 | * @author kpali
12 | */
13 | @Primary
14 | @Component
15 | public class MyTaskFlowScheduler extends DefaultTaskFlowScheduler {
16 | }
17 |
--------------------------------------------------------------------------------
/wolf-flow-sample-cluster/src/main/java/me/kpali/wolfflow/sample/cluster/taskflow/MyTaskLogger.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.sample.cluster.taskflow;
2 |
3 | import me.kpali.wolfflow.core.logger.impl.DefaultTaskLogger;
4 | import org.springframework.context.annotation.Primary;
5 | import org.springframework.stereotype.Component;
6 |
7 | /**
8 | * 可以覆写默认任务日志器的方法实现自定义,推荐使用数据库DAO实现日志持久化到硬盘。本示例为简单起见仍然使用默认实现存储到内存
9 | * (可选)
10 | *
11 | * @author kpali
12 | */
13 | @Primary
14 | @Component
15 | public class MyTaskLogger extends DefaultTaskLogger {
16 | }
17 |
--------------------------------------------------------------------------------
/wolf-flow-sample-cluster/src/main/java/me/kpali/wolfflow/sample/cluster/util/SpringContextUtil.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.sample.cluster.util;
2 |
3 | import org.springframework.beans.BeansException;
4 | import org.springframework.context.ApplicationContext;
5 | import org.springframework.context.ApplicationContextAware;
6 | import org.springframework.stereotype.Component;
7 |
8 | @Component
9 | public class SpringContextUtil implements ApplicationContextAware {
10 | private static ApplicationContext applicationContext = null;
11 |
12 | @Override
13 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
14 | SpringContextUtil.applicationContext = applicationContext;
15 | }
16 |
17 | public static ApplicationContext getApplicationContext() {
18 | return applicationContext;
19 | }
20 |
21 | public static Object getBean(String beanId) {
22 | return applicationContext.getBean(beanId);
23 | }
24 |
25 | public static T getBean(Class requiredType) {
26 | return applicationContext.getBean(requiredType);
27 | }
28 | }
29 |
30 |
--------------------------------------------------------------------------------
/wolf-flow-sample-cluster/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | spring.application.name=wolf-flow-sample-cluster
--------------------------------------------------------------------------------
/wolf-flow-sample-cluster/src/main/resources/quartz.properties:
--------------------------------------------------------------------------------
1 | org.quartz.scheduler.instanceName = MyScheduler
2 | org.quartz.threadPool.threadCount = 10
3 | org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
4 | org.quartz.jobStore.misfireThreshold = 60000
--------------------------------------------------------------------------------
/wolf-flow-sample-cluster/src/main/resources/redisson.yaml:
--------------------------------------------------------------------------------
1 | singleServerConfig:
2 | address: "redis://192.168.232.171:6379"
--------------------------------------------------------------------------------
/wolf-flow-sample-cluster/src/test/java/me/kpali/wolfflow/sample/cluster/WolfFlowSampleClusterApplicationTests.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.sample.cluster;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import me.kpali.wolfflow.core.exception.TaskFlowLogException;
5 | import me.kpali.wolfflow.core.exception.TaskLogException;
6 | import me.kpali.wolfflow.core.logger.ITaskFlowLogger;
7 | import me.kpali.wolfflow.core.logger.ITaskLogger;
8 | import me.kpali.wolfflow.core.model.TaskFlowLog;
9 | import me.kpali.wolfflow.core.model.TaskLog;
10 | import me.kpali.wolfflow.core.model.TaskLogResult;
11 | import me.kpali.wolfflow.core.scheduler.ITaskFlowScheduler;
12 | import org.junit.jupiter.api.Test;
13 | import org.slf4j.Logger;
14 | import org.slf4j.LoggerFactory;
15 | import org.springframework.beans.factory.annotation.Autowired;
16 | import org.springframework.boot.test.context.SpringBootTest;
17 |
18 | import java.util.List;
19 |
20 | @SpringBootTest
21 | public class WolfFlowSampleClusterApplicationTests {
22 | private static final Logger logger = LoggerFactory.getLogger(WolfFlowSampleClusterApplicationTests.class);
23 |
24 | @Autowired
25 | ITaskFlowScheduler taskFlowScheduler;
26 | @Autowired
27 | ITaskFlowLogger taskFlowLogger;
28 | @Autowired
29 | ITaskLogger taskLogger;
30 |
31 | @Test
32 | public void taskFlowExecuteTest() {
33 | ObjectMapper objectMapper = new ObjectMapper();
34 | try {
35 | long taskFlowLogId1 = taskFlowScheduler.executeTo(100L, 5L, null);
36 | logger.info(">>>>>>>>>> Task flow log id: " + taskFlowLogId1);
37 | //Thread.sleep(1000);
38 | //taskFlowScheduler.stop(taskFlowLogId1);
39 | this.waitDoneAndPrintLog(taskFlowLogId1);
40 | List taskStatusList1 = taskLogger.listTaskStatus(100L);
41 | logger.info(">>>>>>>>>> Finished, status of tasks: ");
42 | logger.info(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(taskStatusList1));
43 |
44 | long taskFlowLogId2 = taskFlowScheduler.executeTo(100L, 6L, null);
45 | logger.info(">>>>>>>>>> Task flow log id: " + taskFlowLogId2);
46 | this.waitDoneAndPrintLog(taskFlowLogId2);
47 | List taskStatusList2 = taskLogger.listTaskStatus(100L);
48 | logger.info(">>>>>>>>>> Finished, status of tasks: ");
49 | logger.info(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(taskStatusList2));
50 | } catch (Exception e) {
51 | e.printStackTrace();
52 | }
53 | }
54 |
55 | private void waitDoneAndPrintLog(long taskFLowLogId) throws TaskFlowLogException, TaskLogException {
56 | while (true) {
57 | TaskFlowLog taskFlowLog = taskFlowLogger.get(taskFLowLogId);
58 | if (!taskFlowLogger.isInProgress(taskFlowLog)) {
59 | List taskLogList = taskLogger.list(taskFLowLogId);
60 | for (TaskLog taskLog : taskLogList) {
61 | TaskLogResult taskLogResult = taskLogger.query(taskLog.getLogFileId(), 1);
62 | if (taskLogResult != null) {
63 | logger.info(">>>>>>>>>> Task [" + taskLog.getTaskId() + "] log contents: ");
64 | logger.info(taskLogResult.getLogContent());
65 | }
66 | }
67 | break;
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/wolf-flow-sample/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 2.2.4.RELEASE
9 |
10 |
11 | me.kpali
12 | wolf-flow-sample
13 | 1.0.0
14 | wolf-flow-sample ${project.version}
15 | Wolf flow Sample
16 |
17 |
18 |
19 | org.springframework.boot
20 | spring-boot-starter
21 |
22 |
23 | org.springframework.boot
24 | spring-boot-starter-web
25 |
26 |
27 |
28 | org.springframework.boot
29 | spring-boot-devtools
30 | runtime
31 | true
32 |
33 |
34 | org.springframework.boot
35 | spring-boot-starter-test
36 | test
37 |
38 |
39 | org.junit.vintage
40 | junit-vintage-engine
41 |
42 |
43 |
44 |
45 |
46 | me.kpali
47 | wolf-flow-spring-boot-starter
48 | 2.1.1
49 |
50 |
51 |
52 |
53 |
54 |
55 | org.springframework.boot
56 | spring-boot-maven-plugin
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/wolf-flow-sample/src/main/java/me/kpali/wolfflow/sample/WolfFlowSampleApplication.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.sample;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class WolfFlowSampleApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(WolfFlowSampleApplication.class, args);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/wolf-flow-sample/src/main/java/me/kpali/wolfflow/sample/controller/MetricsController.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.sample.controller;
2 |
3 | import me.kpali.wolfflow.core.monitor.IMonitor;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.web.bind.annotation.GetMapping;
6 | import org.springframework.web.bind.annotation.RestController;
7 |
8 | @RestController
9 | public class MetricsController {
10 | @Autowired
11 | IMonitor monitor;
12 |
13 | @GetMapping(value = "/prometheus", produces = {"text/plain; version=0.0.4; charset=utf-8"})
14 | public String getMetrics() {
15 | String response = monitor.scrape();
16 | return response;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/wolf-flow-sample/src/main/java/me/kpali/wolfflow/sample/controller/TriggerController.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.sample.controller;
2 |
3 | import me.kpali.wolfflow.core.exception.TaskFlowTriggerException;
4 | import me.kpali.wolfflow.core.scheduler.ITaskFlowScheduler;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.web.bind.annotation.GetMapping;
7 | import org.springframework.web.bind.annotation.PathVariable;
8 | import org.springframework.web.bind.annotation.RestController;
9 |
10 | @RestController
11 | public class TriggerController {
12 | @Autowired
13 | ITaskFlowScheduler taskFlowScheduler;
14 |
15 | @GetMapping(value = "/trigger/{taskFlowId}")
16 | public void trigger(@PathVariable Long taskFlowId) throws TaskFlowTriggerException {
17 | taskFlowScheduler.execute(taskFlowId, null);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/wolf-flow-sample/src/main/java/me/kpali/wolfflow/sample/listener/ApplicationReadyEventListener.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.sample.listener;
2 |
3 | import me.kpali.wolfflow.core.launcher.Launcher;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.boot.context.event.ApplicationReadyEvent;
6 | import org.springframework.context.ApplicationListener;
7 | import org.springframework.stereotype.Component;
8 |
9 | /**
10 | * 程序启动完成事件监听,在程序启动后启动任务流相关的后台线程
11 | * (必要)
12 | *
13 | * @author kpali
14 | */
15 | @Component
16 | public class ApplicationReadyEventListener implements ApplicationListener {
17 | @Autowired
18 | private Launcher launcher;
19 |
20 | @Override
21 | public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
22 | this.launcher.startup();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/wolf-flow-sample/src/main/java/me/kpali/wolfflow/sample/listener/TaskFlowEventListener.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.sample.listener;
2 |
3 | import me.kpali.wolfflow.core.event.ScheduleStatusChangeEvent;
4 | import me.kpali.wolfflow.core.event.TaskFlowStatusChangeEvent;
5 | import me.kpali.wolfflow.core.event.TaskStatusChangeEvent;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 | import org.springframework.context.event.EventListener;
9 | import org.springframework.stereotype.Component;
10 |
11 | /**
12 | * 任务流事件监听
13 | * (可选)
14 | *
15 | * @author kpali
16 | */
17 | @Component
18 | public class TaskFlowEventListener {
19 | private static final Logger logger = LoggerFactory.getLogger(TaskFlowEventListener.class);
20 |
21 | @EventListener
22 | public void taskFlowScheduleStatusChange(ScheduleStatusChangeEvent event) {
23 | // 任务流调度状态变更监听,主要为定时任务流,状态有[加入调度、更新调度、调度失败]等
24 | }
25 |
26 | @EventListener
27 | public void taskFlowStatusChange(TaskFlowStatusChangeEvent event) {
28 | // 任务流状态变更监听,状态有[等待执行、执行中、执行成功、执行失败、停止中]等
29 | logger.info(">>>>>>>>>> Task flow [{}] status changed to: {}", event.getTaskFlowStatus().getTaskFlow().getId(), event.getTaskFlowStatus().getStatus());
30 | }
31 |
32 | @EventListener
33 | public void taskStatusChange(TaskStatusChangeEvent event) {
34 | // 任务状态变更监听,状态有[等待执行、执行中、执行成功、执行失败、停止中、跳过]等
35 | logger.info(">>>>>>>>>> Task [{}] status changed to: {}", event.getTaskStatus().getTask().getId(), event.getTaskStatus().getStatus());
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/wolf-flow-sample/src/main/java/me/kpali/wolfflow/sample/taskflow/MyTask.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.sample.taskflow;
2 |
3 | import me.kpali.wolfflow.core.exception.TaskExecuteException;
4 | import me.kpali.wolfflow.core.exception.TaskInterruptedException;
5 | import me.kpali.wolfflow.core.exception.TaskStopException;
6 | import me.kpali.wolfflow.core.logger.ITaskLogger;
7 | import me.kpali.wolfflow.core.model.Task;
8 | import me.kpali.wolfflow.core.model.TaskContextKey;
9 | import me.kpali.wolfflow.core.util.context.TaskContextWrapper;
10 | import me.kpali.wolfflow.core.util.context.TaskFlowContextWrapper;
11 | import me.kpali.wolfflow.sample.util.SpringContextUtil;
12 |
13 | import java.util.concurrent.ConcurrentHashMap;
14 |
15 | /**
16 | * 自定义任务,覆写父类的方法,实现自定义任务的执行内容
17 | * (必要)
18 | *
19 | * @author kpali
20 | */
21 | public class MyTask extends Task {
22 | private boolean requiredToStop = false;
23 |
24 | @Override
25 | public void execute(ConcurrentHashMap context) throws TaskExecuteException, TaskInterruptedException {
26 | try {
27 | ITaskLogger taskLogger = SpringContextUtil.getBean(ITaskLogger.class);
28 | TaskFlowContextWrapper taskFlowContextWrapper = new TaskFlowContextWrapper(context);
29 | ConcurrentHashMap taskContext = taskFlowContextWrapper.getTaskContext(this.getId().toString());
30 | TaskContextWrapper taskContextWrapper = new TaskContextWrapper(taskContext);
31 | Long taskLogId = taskContextWrapper.getValue(TaskContextKey.TASK_LOG_ID, Long.class);
32 | String taskLogFileId = taskContextWrapper.getValue(TaskContextKey.TASK_LOG_FILE_ID, String.class);
33 | taskLogger.log(taskLogFileId, "Task executing...", false);
34 | taskLogger.log(taskLogFileId, "Second line...\rThird line...\nFourth line...\r\nFifth line...", false);
35 | if (requiredToStop) {
36 | taskLogger.log(taskLogFileId, "Task execution is terminated", true);
37 | throw new TaskInterruptedException("Task execution is terminated");
38 | }
39 | taskLogger.log(taskLogFileId, "Task execution finished", true);
40 | } catch (TaskInterruptedException e) {
41 | throw e;
42 | } catch (Exception e) {
43 | throw new TaskExecuteException(e);
44 | }
45 | }
46 |
47 | @Override
48 | public void stop(ConcurrentHashMap context) throws TaskStopException {
49 | this.requiredToStop = true;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/wolf-flow-sample/src/main/java/me/kpali/wolfflow/sample/taskflow/MyTaskFlowQuerier.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.sample.taskflow;
2 |
3 | import me.kpali.wolfflow.core.exception.TaskFlowQueryException;
4 | import me.kpali.wolfflow.core.model.Link;
5 | import me.kpali.wolfflow.core.model.TaskFlow;
6 | import me.kpali.wolfflow.core.querier.impl.DefaultTaskFlowQuerier;
7 | import org.springframework.context.annotation.Primary;
8 | import org.springframework.stereotype.Component;
9 |
10 | import java.util.ArrayList;
11 | import java.util.List;
12 | import java.util.stream.Collectors;
13 |
14 | /**
15 | * 自定义任务流查询器,覆写父类的方法,实现自定义任务流查询器
16 | * (必要)
17 | *
18 | * @author kpali
19 | */
20 | @Primary
21 | @Component
22 | public class MyTaskFlowQuerier extends DefaultTaskFlowQuerier {
23 | @Override
24 | public TaskFlow getTaskFlow(Long taskFlowId) throws TaskFlowQueryException {
25 | List taskFlowList = this.listTaskFlow();
26 | return taskFlowList.stream().filter(taskFlow -> {
27 | return taskFlow.getId().equals(taskFlowId);
28 | }).findFirst().get();
29 | }
30 |
31 | @Override
32 | public List listCronTaskFlow() throws TaskFlowQueryException {
33 | List taskFlowList = this.listTaskFlow();
34 | return taskFlowList.stream().filter(taskFlow -> {
35 | return (taskFlow.getCron() != null && !taskFlow.getCron().trim().isEmpty());
36 | }).collect(Collectors.toList());
37 | }
38 |
39 | private List listTaskFlow() {
40 | /**
41 | * 示例拓扑图:
42 | * --> 9
43 | * 1 --> 2 --> 4 | ^
44 | * \ \ ^ | |
45 | * \ v / / --> 8
46 | * --> 3 --> 5 --> 6
47 | * \ |
48 | * \ v
49 | * --> 7
50 | * 10 --> 11
51 | */
52 |
53 | List taskFlowList = new ArrayList<>();
54 |
55 | TaskFlow taskFlow = new TaskFlow();
56 | taskFlow.setId(100L);
57 | taskFlow.setTaskList(new ArrayList<>());
58 | taskFlow.setLinkList(new ArrayList<>());
59 |
60 | MyTask myTask1 = new MyTask();
61 | myTask1.setId(1L);
62 | MyTask myTask2 = new MyTask();
63 | myTask2.setId(2L);
64 | MyTask myTask3 = new MyTask();
65 | myTask3.setId(3L);
66 | MyTask myTask4 = new MyTask();
67 | myTask4.setId(4L);
68 | MyTask myTask5 = new MyTask();
69 | myTask5.setId(5L);
70 | MyTask myTask6 = new MyTask();
71 | myTask6.setId(6L);
72 | MyTask myTask7 = new MyTask();
73 | myTask7.setId(7L);
74 | MyTask myTask8 = new MyTask();
75 | myTask8.setId(8L);
76 | MyTask myTask9 = new MyTask();
77 | myTask9.setId(9L);
78 | MyTask myTask10 = new MyTask();
79 | myTask10.setId(10L);
80 | MyTask myTask11 = new MyTask();
81 | myTask11.setId(11L);
82 | taskFlow.getTaskList().add(myTask3);
83 | taskFlow.getTaskList().add(myTask5);
84 | taskFlow.getTaskList().add(myTask1);
85 | taskFlow.getTaskList().add(myTask10);
86 | taskFlow.getTaskList().add(myTask9);
87 | taskFlow.getTaskList().add(myTask6);
88 | taskFlow.getTaskList().add(myTask4);
89 | taskFlow.getTaskList().add(myTask2);
90 | taskFlow.getTaskList().add(myTask7);
91 | taskFlow.getTaskList().add(myTask11);
92 | taskFlow.getTaskList().add(myTask8);
93 |
94 | taskFlow.getLinkList().add(new Link(1L, 2L));
95 | taskFlow.getLinkList().add(new Link(1L, 3L));
96 | taskFlow.getLinkList().add(new Link(2L, 3L));
97 | taskFlow.getLinkList().add(new Link(2L, 4L));
98 | taskFlow.getLinkList().add(new Link(3L, 4L));
99 | taskFlow.getLinkList().add(new Link(3L, 5L));
100 | taskFlow.getLinkList().add(new Link(5L, 6L));
101 | taskFlow.getLinkList().add(new Link(5L, 7L));
102 | taskFlow.getLinkList().add(new Link(6L, 7L));
103 | taskFlow.getLinkList().add(new Link(5L, 8L));
104 | taskFlow.getLinkList().add(new Link(5L, 9L));
105 | taskFlow.getLinkList().add(new Link(8L, 9L));
106 | taskFlow.getLinkList().add(new Link(10L, 11L));
107 |
108 | //taskFlow.setCron("0 * * * * ?");
109 | //taskFlow.setFromTaskId(1L);
110 |
111 | taskFlowList.add(taskFlow);
112 |
113 | return taskFlowList;
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/wolf-flow-sample/src/main/java/me/kpali/wolfflow/sample/util/SpringContextUtil.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.sample.util;
2 |
3 | import org.springframework.beans.BeansException;
4 | import org.springframework.context.ApplicationContext;
5 | import org.springframework.context.ApplicationContextAware;
6 | import org.springframework.stereotype.Component;
7 |
8 | @Component
9 | public class SpringContextUtil implements ApplicationContextAware {
10 | private static ApplicationContext applicationContext = null;
11 |
12 | @Override
13 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
14 | SpringContextUtil.applicationContext = applicationContext;
15 | }
16 |
17 | public static ApplicationContext getApplicationContext() {
18 | return applicationContext;
19 | }
20 |
21 | public static Object getBean(String beanId) {
22 | return applicationContext.getBean(beanId);
23 | }
24 |
25 | public static T getBean(Class requiredType) {
26 | return applicationContext.getBean(requiredType);
27 | }
28 | }
29 |
30 |
--------------------------------------------------------------------------------
/wolf-flow-sample/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | spring.application.name=wolf-flow-sample
--------------------------------------------------------------------------------
/wolf-flow-sample/src/main/resources/quartz.properties:
--------------------------------------------------------------------------------
1 | org.quartz.scheduler.instanceName = MyScheduler
2 | org.quartz.threadPool.threadCount = 10
3 | org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
4 | org.quartz.jobStore.misfireThreshold = 60000
--------------------------------------------------------------------------------
/wolf-flow-sample/src/test/java/me/kpali/wolfflow/sample/WolfFlowSampleApplicationTests.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.sample;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import me.kpali.wolfflow.core.exception.TaskFlowLogException;
5 | import me.kpali.wolfflow.core.exception.TaskLogException;
6 | import me.kpali.wolfflow.core.logger.ITaskFlowLogger;
7 | import me.kpali.wolfflow.core.logger.ITaskLogger;
8 | import me.kpali.wolfflow.core.model.TaskFlowLog;
9 | import me.kpali.wolfflow.core.model.TaskLog;
10 | import me.kpali.wolfflow.core.model.TaskLogResult;
11 | import me.kpali.wolfflow.core.scheduler.ITaskFlowScheduler;
12 | import org.junit.jupiter.api.Test;
13 | import org.slf4j.Logger;
14 | import org.slf4j.LoggerFactory;
15 | import org.springframework.beans.factory.annotation.Autowired;
16 | import org.springframework.boot.test.context.SpringBootTest;
17 |
18 | import java.util.List;
19 |
20 | @SpringBootTest
21 | public class WolfFlowSampleApplicationTests {
22 | private static final Logger logger = LoggerFactory.getLogger(WolfFlowSampleApplicationTests.class);
23 |
24 | @Autowired
25 | ITaskFlowScheduler taskFlowScheduler;
26 | @Autowired
27 | ITaskFlowLogger taskFlowLogger;
28 | @Autowired
29 | ITaskLogger taskLogger;
30 |
31 | @Test
32 | public void taskFlowExecuteTest() {
33 | ObjectMapper objectMapper = new ObjectMapper();
34 | try {
35 | long taskFlowLogId1 = taskFlowScheduler.execute(100L, 10L, null);
36 | logger.info(">>>>>>>>>> Task flow log id: " + taskFlowLogId1);
37 | //Thread.sleep(1000);
38 | //taskFlowScheduler.stop(taskFlowLogId1);
39 | this.waitDoneAndPrintLog(taskFlowLogId1);
40 | List taskStatusList1 = taskLogger.listTaskStatus(100L);
41 | logger.info(">>>>>>>>>> Finished, status of tasks: ");
42 | logger.info(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(taskStatusList1));
43 |
44 | long taskFlowLogId2 = taskFlowScheduler.executeFrom(100L, 11L, null);
45 | logger.info(">>>>>>>>>> Task flow log id: " + taskFlowLogId2);
46 | this.waitDoneAndPrintLog(taskFlowLogId2);
47 | List taskStatusList2 = taskLogger.listTaskStatus(100L);
48 | logger.info(">>>>>>>>>> Finished, status of tasks: ");
49 | logger.info(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(taskStatusList2));
50 | } catch (Exception e) {
51 | e.printStackTrace();
52 | }
53 | }
54 |
55 | private void waitDoneAndPrintLog(long taskFlowLogId) throws TaskFlowLogException, TaskLogException {
56 | while (true) {
57 | TaskFlowLog taskFlowLog = taskFlowLogger.get(taskFlowLogId);
58 | if (!taskFlowLogger.isInProgress(taskFlowLog)) {
59 | List taskLogList = taskLogger.list(taskFlowLogId);
60 | for (TaskLog taskLog : taskLogList) {
61 | TaskLogResult taskLogResult = taskLogger.query(taskLog.getLogFileId(), 1);
62 | if (taskLogResult != null) {
63 | logger.info(">>>>>>>>>> Task [" + taskLog.getTaskId() + "] log contents: ");
64 | logger.info(taskLogResult.getLogContent());
65 | }
66 | }
67 | break;
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/wolf-flow-spring-boot-starter/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | me.kpali
7 | wolf-flow
8 | 2.1.1
9 |
10 | wolf-flow-spring-boot-starter
11 | wolf-flow-spring-boot-starter ${project.version}
12 |
13 |
14 |
15 | org.springframework.boot
16 | spring-boot-starter
17 | provided
18 |
19 |
20 |
21 | me.kpali
22 | wolf-flow-core
23 | ${project.version}
24 |
25 |
26 |
27 | org.springframework.boot
28 | spring-boot-autoconfigure
29 | provided
30 |
31 |
32 | org.springframework.boot
33 | spring-boot-configuration-processor
34 | true
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/wolf-flow-spring-boot-starter/src/main/java/me/kpali/wolfflow/autoconfigure/WolfFlowAutoConfiguration.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.autoconfigure;
2 |
3 | import me.kpali.wolfflow.autoconfigure.config.*;
4 | import me.kpali.wolfflow.autoconfigure.properties.ClusterProperties;
5 | import me.kpali.wolfflow.autoconfigure.properties.ExecutorProperties;
6 | import me.kpali.wolfflow.autoconfigure.properties.SchedulerProperties;
7 | import org.springframework.boot.context.properties.EnableConfigurationProperties;
8 | import org.springframework.context.annotation.Configuration;
9 | import org.springframework.context.annotation.Import;
10 |
11 | /**
12 | * 自动配置
13 | *
14 | * @author kpali
15 | */
16 | @EnableConfigurationProperties({SchedulerProperties.class,
17 | ExecutorProperties.class,
18 | ClusterProperties.class})
19 | @Import({UtilConfiguration.class,
20 | EventPublisherConfiguration.class,
21 | SchedulerConfiguration.class,
22 | ExecutorConfiguration.class,
23 | QuerierConfiguration.class,
24 | LoggerConfiguration.class,
25 | ClusterConfiguration.class,
26 | MonitorConfiguration.class,
27 | LauncherConfiguration.class})
28 | @Configuration
29 | public class WolfFlowAutoConfiguration {
30 | }
31 |
--------------------------------------------------------------------------------
/wolf-flow-spring-boot-starter/src/main/java/me/kpali/wolfflow/autoconfigure/config/ClusterConfiguration.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.autoconfigure.config;
2 |
3 | import me.kpali.wolfflow.autoconfigure.properties.ClusterProperties;
4 | import me.kpali.wolfflow.core.config.ClusterConfig;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.ComponentScan;
7 |
8 | /**
9 | * 集群控制器配置
10 | *
11 | * @author kpali
12 | */
13 | @ComponentScan(basePackages = {"me.kpali.wolfflow.core.cluster"})
14 | public class ClusterConfiguration {
15 | @Bean
16 | public ClusterConfig getClusterConfig(ClusterProperties clusterProperties) {
17 | ClusterConfig clusterConfig = new ClusterConfig();
18 | clusterConfig.setNodeHeartbeatInterval(clusterProperties.getNodeHeartbeatInterval());
19 | clusterConfig.setNodeHeartbeatDuration(clusterProperties.getNodeHeartbeatDuration());
20 | clusterConfig.setGenerateNodeIdLockLeaseTime(clusterProperties.getGenerateNodeIdLockLeaseTime());
21 | clusterConfig.setTaskFlowLogLockWaitTime(clusterProperties.getTaskFlowLogLockWaitTime());
22 | clusterConfig.setTaskFlowLogLockLeaseTime(clusterProperties.getTaskFlowLogLockLeaseTime());
23 | clusterConfig.setTaskLogLockWaitTime(clusterProperties.getTaskLogLockWaitTime());
24 | clusterConfig.setTaskLogLockLeaseTime(clusterProperties.getTaskLogLockLeaseTime());
25 | return clusterConfig;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/wolf-flow-spring-boot-starter/src/main/java/me/kpali/wolfflow/autoconfigure/config/EventPublisherConfiguration.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.autoconfigure.config;
2 |
3 | import org.springframework.context.annotation.ComponentScan;
4 |
5 | /**
6 | * 事件发布器配置
7 | *
8 | * @author kpali
9 | */
10 | @ComponentScan(basePackages = {"me.kpali.wolfflow.core.event"})
11 | public class EventPublisherConfiguration {
12 | }
13 |
--------------------------------------------------------------------------------
/wolf-flow-spring-boot-starter/src/main/java/me/kpali/wolfflow/autoconfigure/config/ExecutorConfiguration.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.autoconfigure.config;
2 |
3 | import me.kpali.wolfflow.autoconfigure.properties.ExecutorProperties;
4 | import me.kpali.wolfflow.core.config.ExecutorConfig;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.ComponentScan;
7 |
8 | /**
9 | * 执行器配置
10 | *
11 | * @author kpali
12 | */
13 | @ComponentScan(basePackages = {"me.kpali.wolfflow.core.executor"})
14 | public class ExecutorConfiguration {
15 | @Bean
16 | public ExecutorConfig getExecutorConfig(ExecutorProperties executorProperties) {
17 | ExecutorConfig executorConfig = new ExecutorConfig();
18 | executorConfig.setCorePoolSize(executorProperties.getCorePoolSize());
19 | executorConfig.setMaximumPoolSize(executorProperties.getMaximumPoolSize());
20 | return executorConfig;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/wolf-flow-spring-boot-starter/src/main/java/me/kpali/wolfflow/autoconfigure/config/LauncherConfiguration.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.autoconfigure.config;
2 |
3 | import org.springframework.context.annotation.ComponentScan;
4 |
5 | /**
6 | * 启动器配置
7 | *
8 | * @author kpali
9 | */
10 | @ComponentScan(basePackages = {"me.kpali.wolfflow.core.launcher"})
11 | public class LauncherConfiguration {
12 | }
13 |
--------------------------------------------------------------------------------
/wolf-flow-spring-boot-starter/src/main/java/me/kpali/wolfflow/autoconfigure/config/LoggerConfiguration.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.autoconfigure.config;
2 |
3 | import org.springframework.context.annotation.ComponentScan;
4 |
5 | /**
6 | * 日志器配置
7 | *
8 | * @author kpali
9 | */
10 | @ComponentScan(basePackages = {"me.kpali.wolfflow.core.logger"})
11 | public class LoggerConfiguration {
12 | }
13 |
--------------------------------------------------------------------------------
/wolf-flow-spring-boot-starter/src/main/java/me/kpali/wolfflow/autoconfigure/config/MonitorConfiguration.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.autoconfigure.config;
2 |
3 | import org.springframework.context.annotation.ComponentScan;
4 |
5 | /**
6 | * 监控配置
7 | *
8 | * @author kpali
9 | */
10 | @ComponentScan(basePackages = {"me.kpali.wolfflow.core.monitor"})
11 | public class MonitorConfiguration {
12 | }
13 |
--------------------------------------------------------------------------------
/wolf-flow-spring-boot-starter/src/main/java/me/kpali/wolfflow/autoconfigure/config/QuerierConfiguration.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.autoconfigure.config;
2 |
3 | import org.springframework.context.annotation.ComponentScan;
4 |
5 | /**
6 | * 查询器配置
7 | *
8 | * @author kpali
9 | */
10 | @ComponentScan(basePackages = {"me.kpali.wolfflow.core.querier"})
11 | public class QuerierConfiguration {
12 | }
13 |
--------------------------------------------------------------------------------
/wolf-flow-spring-boot-starter/src/main/java/me/kpali/wolfflow/autoconfigure/config/SchedulerConfiguration.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.autoconfigure.config;
2 |
3 | import me.kpali.wolfflow.autoconfigure.properties.SchedulerProperties;
4 | import me.kpali.wolfflow.core.config.SchedulerConfig;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.ComponentScan;
7 |
8 | /**
9 | * 调度器配置
10 | *
11 | * @author kpali
12 | */
13 | @ComponentScan(basePackages = {"me.kpali.wolfflow.core.scheduler"})
14 | public class SchedulerConfiguration {
15 | @Bean
16 | public SchedulerConfig getSchedulerConfig(SchedulerProperties schedulerProperties) {
17 | SchedulerConfig schedulerConfig = new SchedulerConfig();
18 | schedulerConfig.setExecRequestScanInterval(schedulerProperties.getExecRequestScanInterval());
19 | schedulerConfig.setCronScanInterval(schedulerProperties.getCronScanInterval());
20 | schedulerConfig.setCronScanLockWaitTime(schedulerProperties.getCronScanLockWaitTime());
21 | schedulerConfig.setCronScanLockLeaseTime(schedulerProperties.getCronScanLockLeaseTime());
22 | schedulerConfig.setCorePoolSize(schedulerProperties.getCorePoolSize());
23 | schedulerConfig.setMaximumPoolSize(schedulerProperties.getMaximumPoolSize());
24 | return schedulerConfig;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/wolf-flow-spring-boot-starter/src/main/java/me/kpali/wolfflow/autoconfigure/config/UtilConfiguration.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.autoconfigure.config;
2 |
3 | import org.springframework.context.annotation.ComponentScan;
4 |
5 | /**
6 | * 工具配置
7 | *
8 | * @author kpali
9 | */
10 | @ComponentScan(basePackages = {"me.kpali.wolfflow.core.util"})
11 | public class UtilConfiguration {
12 | }
13 |
--------------------------------------------------------------------------------
/wolf-flow-spring-boot-starter/src/main/java/me/kpali/wolfflow/autoconfigure/properties/ClusterProperties.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.autoconfigure.properties;
2 |
3 | import org.springframework.boot.context.properties.ConfigurationProperties;
4 |
5 | /**
6 | * 集群控制器配置
7 | *
8 | * @author kpali
9 | */
10 | @ConfigurationProperties(prefix = "wolf-flow.cluster")
11 | public class ClusterProperties {
12 | private Integer nodeHeartbeatInterval = 30;
13 | private Integer nodeHeartbeatDuration = 90;
14 | private Integer generateNodeIdLockLeaseTime = 60;
15 | private Integer taskFlowLogLockWaitTime = 10;
16 | private Integer taskFlowLogLockLeaseTime = 15;
17 | private Integer taskLogLockWaitTime = 10;
18 | private Integer taskLogLockLeaseTime = 15;
19 |
20 | public Integer getNodeHeartbeatInterval() {
21 | return nodeHeartbeatInterval;
22 | }
23 |
24 | public void setNodeHeartbeatInterval(Integer nodeHeartbeatInterval) {
25 | this.nodeHeartbeatInterval = nodeHeartbeatInterval;
26 | }
27 |
28 | public Integer getNodeHeartbeatDuration() {
29 | return nodeHeartbeatDuration;
30 | }
31 |
32 | public void setNodeHeartbeatDuration(Integer nodeHeartbeatDuration) {
33 | this.nodeHeartbeatDuration = nodeHeartbeatDuration;
34 | }
35 |
36 | public Integer getGenerateNodeIdLockLeaseTime() {
37 | return generateNodeIdLockLeaseTime;
38 | }
39 |
40 | public void setGenerateNodeIdLockLeaseTime(Integer generateNodeIdLockLeaseTime) {
41 | this.generateNodeIdLockLeaseTime = generateNodeIdLockLeaseTime;
42 | }
43 |
44 | public Integer getTaskFlowLogLockWaitTime() {
45 | return taskFlowLogLockWaitTime;
46 | }
47 |
48 | public void setTaskFlowLogLockWaitTime(Integer taskFlowLogLockWaitTime) {
49 | this.taskFlowLogLockWaitTime = taskFlowLogLockWaitTime;
50 | }
51 |
52 | public Integer getTaskFlowLogLockLeaseTime() {
53 | return taskFlowLogLockLeaseTime;
54 | }
55 |
56 | public void setTaskFlowLogLockLeaseTime(Integer taskFlowLogLockLeaseTime) {
57 | this.taskFlowLogLockLeaseTime = taskFlowLogLockLeaseTime;
58 | }
59 |
60 | public Integer getTaskLogLockWaitTime() {
61 | return taskLogLockWaitTime;
62 | }
63 |
64 | public void setTaskLogLockWaitTime(Integer taskLogLockWaitTime) {
65 | this.taskLogLockWaitTime = taskLogLockWaitTime;
66 | }
67 |
68 | public Integer getTaskLogLockLeaseTime() {
69 | return taskLogLockLeaseTime;
70 | }
71 |
72 | public void setTaskLogLockLeaseTime(Integer taskLogLockLeaseTime) {
73 | this.taskLogLockLeaseTime = taskLogLockLeaseTime;
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/wolf-flow-spring-boot-starter/src/main/java/me/kpali/wolfflow/autoconfigure/properties/ExecutorProperties.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.autoconfigure.properties;
2 |
3 | import org.springframework.boot.context.properties.ConfigurationProperties;
4 |
5 | /**
6 | * 执行器配置
7 | *
8 | * @author kpali
9 | */
10 | @ConfigurationProperties(prefix = "wolf-flow.executor")
11 | public class ExecutorProperties {
12 | private Integer corePoolSize = 30;
13 | private Integer maximumPoolSize = 30;
14 |
15 | public Integer getCorePoolSize() {
16 | return corePoolSize;
17 | }
18 |
19 | public void setCorePoolSize(Integer corePoolSize) {
20 | this.corePoolSize = corePoolSize;
21 | }
22 |
23 | public Integer getMaximumPoolSize() {
24 | return maximumPoolSize;
25 | }
26 |
27 | public void setMaximumPoolSize(Integer maximumPoolSize) {
28 | this.maximumPoolSize = maximumPoolSize;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/wolf-flow-spring-boot-starter/src/main/java/me/kpali/wolfflow/autoconfigure/properties/SchedulerProperties.java:
--------------------------------------------------------------------------------
1 | package me.kpali.wolfflow.autoconfigure.properties;
2 |
3 | import org.springframework.boot.context.properties.ConfigurationProperties;
4 |
5 | /**
6 | * 调度器配置
7 | *
8 | * @author kpali
9 | */
10 | @ConfigurationProperties(prefix = "wolf-flow.scheduler")
11 | public class SchedulerProperties {
12 | private Integer execRequestScanInterval = 1;
13 | private Integer cronScanInterval = 10;
14 | private Integer cronScanLockWaitTime = 10;
15 | private Integer cronScanLockLeaseTime = 60;
16 | private Integer corePoolSize = 10;
17 | private Integer maximumPoolSize = 10;
18 |
19 | public Integer getExecRequestScanInterval() {
20 | return execRequestScanInterval;
21 | }
22 |
23 | public void setExecRequestScanInterval(Integer execRequestScanInterval) {
24 | this.execRequestScanInterval = execRequestScanInterval;
25 | }
26 |
27 | public Integer getCronScanInterval() {
28 | return cronScanInterval;
29 | }
30 |
31 | public void setCronScanInterval(Integer cronScanInterval) {
32 | this.cronScanInterval = cronScanInterval;
33 | }
34 |
35 | public Integer getCronScanLockWaitTime() {
36 | return cronScanLockWaitTime;
37 | }
38 |
39 | public void setCronScanLockWaitTime(Integer cronScanLockWaitTime) {
40 | this.cronScanLockWaitTime = cronScanLockWaitTime;
41 | }
42 |
43 | public Integer getCronScanLockLeaseTime() {
44 | return cronScanLockLeaseTime;
45 | }
46 |
47 | public void setCronScanLockLeaseTime(Integer cronScanLockLeaseTime) {
48 | this.cronScanLockLeaseTime = cronScanLockLeaseTime;
49 | }
50 |
51 | public Integer getCorePoolSize() {
52 | return corePoolSize;
53 | }
54 |
55 | public void setCorePoolSize(Integer corePoolSize) {
56 | this.corePoolSize = corePoolSize;
57 | }
58 |
59 | public Integer getMaximumPoolSize() {
60 | return maximumPoolSize;
61 | }
62 |
63 | public void setMaximumPoolSize(Integer maximumPoolSize) {
64 | this.maximumPoolSize = maximumPoolSize;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/wolf-flow-spring-boot-starter/src/main/resources/META-INF/spring.factories:
--------------------------------------------------------------------------------
1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
2 | me.kpali.wolfflow.autoconfigure.WolfFlowAutoConfiguration
--------------------------------------------------------------------------------