mirror of
https://gitee.com/dolphinscheduler/DolphinScheduler.git
synced 2024-12-01 19:58:29 +08:00
[Feature][JsonSplit-api] merge code from dev to json2 (#6115)
* [BUG-#5678][Registry]fix registry init node miss (#5686) * [Improvement][UI] Update the update time after the user information is successfully modified (#5684) * improve edit the userinfo success, but the updatetime is not the latest. * Improved shell task execution result log information, adding process.waitFor() and process.exitValue() information to the original log (#5691) Co-authored-by: shenglm <shenglm840722@126.com> * [Feature-#5565][Master Worker-Server] Global Param passed by sense dependencies (#5603) * add globalParams new plan with varPool * add unit test * add python task varPoolParams Co-authored-by: wangxj <wangxj31> * Issue robot translation judgment changed to Chinese (#5694) Co-authored-by: chenxingchun <438044805@qq.com> * the update function should use post instead of get (#5703) * enhance form verify (#5696) * checkState only supports %s not {} (#5711) * [Fix-5701]When deleting a user, the accessToken associated with the user should also be deleted (#5697) * update * fix the codestyle error * fix the compile error * support rollback * [Fix-5699][UI] Fix update user error in user information (#5700) * [Improvement] the automatically generated spi service name in alert-plugin is wrong (#5676) * bug fix the auto generated spi service can't be recongized * include a new method * [Improvement-5622][project management] Modify the title (#5723) * [Fix-5714] When updating the existing alarm instance, the creation time should't be updated (#5715) * add a new init method. * [Fix#5758] There are some problems in the api documentation that need to be improved (#5759) * add the necessary parameters * openapi improve * fix code style error * [FIX-#5721][master-server] Global params parameter missing (#5757) Co-authored-by: wangxj <wangxj31> * [Fix-5738][UI] The cancel button in the pop-up dialog of `batch copy` and `batch move` doesn't work. (#5739) * Update relatedItems.vue * Update relatedItems.vue * [Improvement#5741][Worker] Improve task process status log (#5776) * [Improvement-5773][server] need to support two parameters related to task (#5774) * add some new parameter for task * restore official properties * improve imports * modify a variable's name Co-authored-by: jiang hua <jiang.hua@zhaopin.com.cn> * [FIX-5786][Improvement][Server] When the Worker turns down, the MasterServer cannot handle the Remove event correctly and throws NPE * [Improvement][Worker] Task log may be lost #5775 (#5783) * [Imporvement #5725][CheckStyle] upgrade checkstyle file (#5789) * [Imporvement #5725][CheckStyle] upgrade checkstyle file Upgrade checkstyle.xml to support checkstyle version 8.24+ * change ci checkstyle version * [Fix-5795][Improvement][Server] The starttime field in the HttpTask log is not displayed as expected. (#5796) * improve timestamp format make the startime in the log of httptask to be easier to read. * fix bad code smell and update the note. * [Imporvement #5621][job instance] start-time and end-time (#5621) (#5797) ·the list of workflow instances is sorted by start time and end time ·This closes #5621 * fix (#5803) Co-authored-by: shuangbofu <fusb@tuya.com> * fix: Remove duplicate "registryClient.close" method calls (#5805) Co-authored-by: wen-hemin <wenhemin@apache.com> * [Improvement][SPI] support load single plugin (#5794) change load operation of 'registry.plugin.dir' * [Improvement][Api Module] refactor registry client, remove spring annotation (#5814) * fix: refactor registry client, remove spring annotation * fix UT * fix UT * fix checkstyle * fix UT * fix UT * fix UT * fix: Rename RegistryCenterUtils method name Co-authored-by: wen-hemin <wenhemin@apache.com> * [Fix-5699][UI] Fix update user error in user information introduced by #5700 (#5735) * [Fix-5726] When we used the UI page, we found some problems such as parameter validation, parameter update shows success but actually work (#5727) * enhance the validation in UI * enchance form verifaction * simplify disable condition * fix: Remove unused class (#5833) Co-authored-by: wen-hemin <wenhemin@apache.com> * [fix-5737] [Bug][Datasource] datsource other param check error (#5835) Co-authored-by: wanggang <wanggy01@servyou.com.cn> * [Fix-5719][K8s] Fix Ingress tls: got map expected array On TLS enabled On Kubernetes [Fix-5719][K8s] Fix Ingress tls: got map expected array On TLS enabled On Kubernetes * [Fix-5825][BUG][WEB] the resource tree in the process definition of latest dev branch can't display correctly (#5826) * resoures-shows-error * fix codestyle error * add license header for new js * fix codesmell * [Improvement-5852][server] Support two parameters related to task for the rest of type of tasks. (#5867) * provide two system parameters to support the rest of type of tasks * provide two system parameters to support the rest of type of tasks * improve test conversion * [Improvement][Fix-5769][UI]When we try to delete the existing dag, the console in web browser would shows exception (#5770) * fix bug * cache the this variable * Avoid self name * fix code style compile error * [Fix-5781][UT] Fix test coverage in sonar (#5817) * build(UT): make jacoco running in offline-instrumentation issue: #5781 * build(UT): remove the jacoco agent dependency in microbench issue: #5781 * [Fix-5808][Server] When we try to transfer data using datax between different types of data sources, the worker will exit with ClassCastException (#5809) * bug fix * fix bug * simplify the code format * add a new parameter to make it easier to understand. * [Fix-5830][Improvement][UI] Improve the selection style in dag edit dialog (#5829) * improve the selection style * update another file * remove unnecessary css part. * [Fix-5904][upgrade]fix dev branch upgrade mysql sql script error (#5821) * fix dev branch upgrade mysql sql script error. * Update naming convention. * [Improvement][Api Module] refactor DataSourceParam and DependentParam, remove spring annotation (#5832) * fix: refactor api utils class, remove spring annotation. * fix: Optimization comments Co-authored-by: wen-hemin <wenhemin@apache.com> * correct the wrong annotion from zk queue implemented to java priority blocking queue (#5906) Co-authored-by: ywang46 <ywang46@paypal.com> * Add a Gitter chat badge to README.md (#5883) * Add Gitter badge * Update README.md Co-authored-by: David <dailidong66@gmail.com> * ci: improve maven connection in CI builds (#5924) issue: #5921 * [Improvement][Master]fix typo (#5934) ·fix typo in MasterBaseTaskExecThread * [Fix-5886][server] Enhanced scheduler delete check (#5936) * Add:Name verification remove the first and last spaces. * Update: wrong word: 'WAITTING' ->'WAITING' * Add: Strengthen verification Co-authored-by: Squid <2824638304@qq.com> * [Improvement-5880][api] Optimized data structure of pagination query API results (#5895) * [5880][refactor]Optimized data structure of pagination query API results - refactor PageInfo and delete returnDataListPaging in API - modify the related Controller and Service and the corresponding Test * Merge branch 'dev' of github.com:apache/dolphinscheduler into dev Conflicts: dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProcessDefinitionServiceImpl.java Co-authored-by: 蔡泽华 <sorea1k@163.com> * [IMPROVEMENT]fix mysql comment error (#5959) * [Improvement][Api]fix typo (#5960) * [Imporvement #5621][job instance] start-time and end-time (#5621) ·the list of workflow instances is sorted by start time and end time ·This closes #5621 * [FIX-5975]queryLastRunningProcess sql in ProcessInstanceMapper.xml (#5980) * [NEW FEATURE][FIX-4385] compensation task add the ability to configure parallelism (#5912) * update * web improved * improve the ui * add the ability to configure the parallelism * update variables * enhance the ut and add necessary note * fix code style * fix code style issue * ensure the complation task in parallel mode can run the right numbers of tasks. * [Improvement][dao]When I search for the keyword description, the web UI shows empty (#5952) * [Bug][WorkerServer] SqlTask NullPointerException #5549 * [Improvement][dao]When I search for the keyword Modify User, the web UI shows empty #5428 * [Improvement][dao]When I search for the keyword Modify User, the web UI shows empty #5428 * [Improvement][dao]When I search for the keyword Modify User, the web UI shows empty #5428 * [Improvement][dao]When I search for the keyword Modify User, the web UI shows empty #5428 * [Improvement][dao]When I search for the keyword Modify User, the web UI shows empty #5428 * [Improvement][dao]When I search for the keyword Modify User, the web UI shows empty #5428 * [Improvement][dao]When I search for the keyword description, the web UI shows empty #5428 * fix the readme typing issue (#5998) * Fix unchecked type conversions * Use indentation level reported by checkstyle * Reorganize CI workflows to fasten the wasted time and resources (#6011) * Add standalone server module to make it easier to develop (#6022) * Task node of SWITCH (#5939) * [Feature-#5273][server-master] Task node of SWITCH (#5922) Co-authored-by: wangxj <wangxj31> * remove description of bonecp (#6030) Co-authored-by: shaojwu <shaojwu@ebay.com> * [Improvement][Api Module]split alert group list-paging interface (#5941) * [Improvement][Api Module]split alert group list-paging interface * [FIX-#6007]Wrong complement date (#6026) * [FIX-#6007]Wrong complement date * [style]Wrong complement date * [Improvement-6024][dist] Remove useless packaging commands (#6029) ·Remove useless packaging commands in dolphinscheduler-bin.xml This closes #6024 Co-authored-by: mask <liuhu@zhiyoutec.com> * [FIX-5908][MasterServer] When executing an compensation task, the execution thread would have a NPE (#5909) * fix the npe in MasterExec * fix the compile error * Add `.asf.yaml` to easily set the GitHub metadata (#6035) * fix dead server cannot stop (#6046) * Enhancement Translation (#6042) * replaced Loading... with i18n * modified Edit zh_CN translation * Delete zh_CN.js Co-authored-by: David <dailidong66@gmail.com> * fix bug #6053 zh_CN.js is lost * [Fix-6038][ui] width of "SQL Statement" in Dag FormLineModal will be shrunk if sql line is too long (#6040) This closes #6038 * [Improvement] Fix inefficient map iterator (#6004) * Fix inefficient map iterator * Use forEach and remove call to valueOf * Modify AbstractParameters * Enhance `StandaloneServer` so that we don't need to update the version number manually (#6074) * Remove invalid character in `.asf.yaml` (#6075) * Remove invalid character `\n` in `.asf.yaml` (#6077) It turns out that the invalid character is `\n` * Add alert server into standalone-server as well and some minor polish (#6087) * Support starting standalone server in Docker image (#6102) Also remove unused class * [Feature-4355][Master-Worker-API] improvements of master and scheduler module (#6095) * [Feature-4355][Master-Worker-API] improvements of master and scheduler module (#6085) * master refactor: 1. spi for task submit and other actions(pause, kill) 2. remove threads for process instance and task instance. 3. add events for process instance and task instance * ut npe * add try catch * code style * fix critical bugs * fix critical bugs * fix critical bugs * fix critical bugs * Remove unused params in SwitchTaskTest (#6109) * fix ut * fix ut * fix ut * fix ut * fix server module ut * fix ut Co-authored-by: Kirs <acm_master@163.com> Co-authored-by: kyoty <echohlne@gmail.com> Co-authored-by: ji04xiaogang <ji04xiaogang@163.com> Co-authored-by: shenglm <shenglm840722@126.com> Co-authored-by: wangxj3 <857234426@qq.com> Co-authored-by: xingchun-chen <55787491+xingchun-chen@users.noreply.github.com> Co-authored-by: chenxingchun <438044805@qq.com> Co-authored-by: Shiwen Cheng <chengshiwen0103@gmail.com> Co-authored-by: Jianchao Wang <akingchao@qq.com> Co-authored-by: Tanvi Moharir <74228962+tanvimoharir@users.noreply.github.com> Co-authored-by: Hua Jiang <jianghuachinacom@163.com> Co-authored-by: jiang hua <jiang.hua@zhaopin.com.cn> Co-authored-by: Wenjun Ruan <861923274@qq.com> Co-authored-by: Tandoy <56899730+Tandoy@users.noreply.github.com> Co-authored-by: 傅双波 <786183073@qq.com> Co-authored-by: shuangbofu <fusb@tuya.com> Co-authored-by: wen-hemin <39549317+wen-hemin@users.noreply.github.com> Co-authored-by: wen-hemin <wenhemin@apache.com> Co-authored-by: geosmart <geosmart@hotmail.com> Co-authored-by: wanggang <wanggy01@servyou.com.cn> Co-authored-by: AzureCN <colorazure@163.com> Co-authored-by: 深刻 <tsund@qq.com> Co-authored-by: zhuangchong <37063904+zhuangchong@users.noreply.github.com> Co-authored-by: Yao WANG <Yao.MR.CN@gmail.com> Co-authored-by: ywang46 <ywang46@paypal.com> Co-authored-by: The Gitter Badger <badger@gitter.im> Co-authored-by: David <dailidong66@gmail.com> Co-authored-by: Squidyu <1297554122@qq.com> Co-authored-by: Squid <2824638304@qq.com> Co-authored-by: soreak <60459867+soreak@users.noreply.github.com> Co-authored-by: 蔡泽华 <sorea1k@163.com> Co-authored-by: yimaixinchen <yimaixinchen@163.com> Co-authored-by: atai-555 <74188560+atai-555@users.noreply.github.com> Co-authored-by: didiaode18 <563646039@qq.com> Co-authored-by: Roy <yongjuncao1213@gmail.com> Co-authored-by: lyxell <alyxell@kth.se> Co-authored-by: Wenjun Ruan <wenjun@apache.org> Co-authored-by: kezhenxu94 <kezhenxu94@apache.org> Co-authored-by: myangle1120 <942542838@qq.com> Co-authored-by: gabry.wu <gabrywu@apache.org> Co-authored-by: shaojwu <shaojwu@ebay.com> Co-authored-by: Shukun Zhang <60541766+andream7@users.noreply.github.com> Co-authored-by: linquan <1175687813@qq.com> Co-authored-by: mask <39329477+Narcasserun@users.noreply.github.com> Co-authored-by: mask <liuhu@zhiyoutec.com> Co-authored-by: RichardStark <49977764+RichardStark@users.noreply.github.com> Co-authored-by: lenboo <baoliang.leon@gmail.com> Co-authored-by: lilyzhou <lj_zhou@outlook.com> Co-authored-by: OS <29528966+lenboo@users.noreply.github.com> Co-authored-by: junfan.zhang <zuston.shacha@gmail.com> Co-authored-by: JinyLeeChina <297062848@qq.com>
This commit is contained in:
parent
aa8301ad36
commit
33ea3eddb9
44
.asf.yaml
Normal file
44
.asf.yaml
Normal file
@ -0,0 +1,44 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
github:
|
||||
description: Apache DolphinScheduler is a distributed and extensible workflow scheduler platform with powerful DAG visual interfaces, dedicated to solving complex job dependencies in the data pipeline and providing various types of jobs available out of box.
|
||||
homepage: https://dolphinscheduler.apache.org/
|
||||
labels:
|
||||
- airflow
|
||||
- schedule
|
||||
- job-scheduler
|
||||
- oozie
|
||||
- task-scheduler
|
||||
- azkaban
|
||||
- distributed-schedule-system
|
||||
- workflow-scheduling-system
|
||||
- etl-dependency
|
||||
- workflow-platform
|
||||
- cronjob-schedule
|
||||
- job-schedule
|
||||
- task-schedule
|
||||
- workflow-schedule
|
||||
- data-schedule
|
||||
enabled_merge_buttons:
|
||||
squash: true
|
||||
merge: false
|
||||
rebase: false
|
||||
protected_branches:
|
||||
dev:
|
||||
required_status_checks:
|
||||
strict: true
|
@ -80,7 +80,7 @@ dolphinscheduler-dist/target/apache-dolphinscheduler-${latest.release.version}-s
|
||||
|
||||
## Thanks
|
||||
|
||||
DolphinScheduler is based on a lot of excellent open-source projects, such as Google guava, guice, grpc, netty, ali bonecp, quartz, and many open-source projects of Apache and so on.
|
||||
DolphinScheduler is based on a lot of excellent open-source projects, such as Google guava, guice, grpc, netty, quartz, and many open-source projects of Apache and so on.
|
||||
We would like to express our deep gratitude to all the open-source projects used in Dolphin Scheduler. We hope that we are not only the beneficiaries of open-source, but also give back to the community. Besides, we hope everyone who have the same enthusiasm and passion for open source could join in and contribute to the open-source community!
|
||||
|
||||
## Get Help
|
||||
|
@ -82,7 +82,7 @@ dolphinscheduler-dist/target/apache-dolphinscheduler-${latest.release.version}-s
|
||||
|
||||
## 感谢
|
||||
|
||||
Dolphin Scheduler使用了很多优秀的开源项目,比如google的guava、guice、grpc,netty,ali的bonecp,quartz,以及apache的众多开源项目等等,
|
||||
Dolphin Scheduler使用了很多优秀的开源项目,比如google的guava、guice、grpc,netty,quartz,以及apache的众多开源项目等等,
|
||||
正是由于站在这些开源项目的肩膀上,才有Dolphin Scheduler的诞生的可能。对此我们对使用的所有开源软件表示非常的感谢!我们也希望自己不仅是开源的受益者,也能成为开源的贡献者,也希望对开源有同样热情和信念的伙伴加入进来,一起为开源献出一份力!
|
||||
|
||||
## 获得帮助
|
||||
|
@ -90,3 +90,18 @@ killasgroup=true
|
||||
redirect_stderr=true
|
||||
stdout_logfile=/dev/fd/1
|
||||
stdout_logfile_maxbytes=0
|
||||
|
||||
[program:standalone]
|
||||
command=%(ENV_DOLPHINSCHEDULER_BIN)s/dolphinscheduler-daemon.sh start standalone-server
|
||||
directory=%(ENV_DOLPHINSCHEDULER_HOME)s
|
||||
priority=999
|
||||
autostart=%(ENV_STANDALONE_START_ENABLED)s
|
||||
autorestart=true
|
||||
startsecs=5
|
||||
stopwaitsecs=3
|
||||
exitcodes=0
|
||||
stopasgroup=true
|
||||
killasgroup=true
|
||||
redirect_stderr=true
|
||||
stdout_logfile=/dev/fd/1
|
||||
stdout_logfile_maxbytes=0
|
||||
|
@ -24,6 +24,7 @@ export WORKER_START_ENABLED=false
|
||||
export API_START_ENABLED=false
|
||||
export ALERT_START_ENABLED=false
|
||||
export LOGGER_START_ENABLED=false
|
||||
export STANDALONE_START_ENABLED=false
|
||||
|
||||
# wait database
|
||||
waitDatabase() {
|
||||
@ -67,12 +68,13 @@ waitZK() {
|
||||
printUsage() {
|
||||
echo -e "Dolphin Scheduler is a distributed and easy-to-expand visual DAG workflow scheduling system,"
|
||||
echo -e "dedicated to solving the complex dependencies in data processing, making the scheduling system out of the box for data processing.\n"
|
||||
echo -e "Usage: [ all | master-server | worker-server | api-server | alert-server ]\n"
|
||||
printf "%-13s: %s\n" "all" "Run master-server, worker-server, api-server and alert-server"
|
||||
printf "%-13s: %s\n" "master-server" "MasterServer is mainly responsible for DAG task split, task submission monitoring."
|
||||
printf "%-13s: %s\n" "worker-server" "WorkerServer is mainly responsible for task execution and providing log services."
|
||||
printf "%-13s: %s\n" "api-server" "ApiServer is mainly responsible for processing requests and providing the front-end UI layer."
|
||||
printf "%-13s: %s\n" "alert-server" "AlertServer mainly include Alarms."
|
||||
echo -e "Usage: [ all | master-server | worker-server | api-server | alert-server | standalone-server ]\n"
|
||||
printf "%-13s: %s\n" "all" "Run master-server, worker-server, api-server and alert-server"
|
||||
printf "%-13s: %s\n" "master-server" "MasterServer is mainly responsible for DAG task split, task submission monitoring."
|
||||
printf "%-13s: %s\n" "worker-server" "WorkerServer is mainly responsible for task execution and providing log services."
|
||||
printf "%-13s: %s\n" "api-server" "ApiServer is mainly responsible for processing requests and providing the front-end UI layer."
|
||||
printf "%-13s: %s\n" "alert-server" "AlertServer mainly include Alarms."
|
||||
printf "%-13s: %s\n" "standalone-server" "Standalone server that uses embedded zookeeper and database, only for testing and demostration."
|
||||
}
|
||||
|
||||
# init config file
|
||||
@ -110,6 +112,9 @@ case "$1" in
|
||||
waitDatabase
|
||||
export ALERT_START_ENABLED=true
|
||||
;;
|
||||
(standalone-server)
|
||||
export STANDALONE_START_ENABLED=true
|
||||
;;
|
||||
(help)
|
||||
printUsage
|
||||
exit 1
|
||||
|
@ -80,7 +80,7 @@ public class MailSender {
|
||||
private String sslTrust;
|
||||
private String showType;
|
||||
private AlertTemplate alertTemplate;
|
||||
private String mustNotNull = "must not be null";
|
||||
private String mustNotNull = " must not be null";
|
||||
|
||||
public MailSender(Map<String, String> config) {
|
||||
|
||||
|
@ -72,8 +72,13 @@
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>jsr305</artifactId>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
|
@ -24,8 +24,6 @@ import org.apache.dolphinscheduler.alert.plugin.AlertPluginManager;
|
||||
import org.apache.dolphinscheduler.alert.processor.AlertRequestProcessor;
|
||||
import org.apache.dolphinscheduler.alert.runner.AlertSender;
|
||||
import org.apache.dolphinscheduler.alert.utils.Constants;
|
||||
import org.apache.dolphinscheduler.spi.plugin.DolphinPluginLoader;
|
||||
import org.apache.dolphinscheduler.spi.plugin.DolphinPluginManagerConfig;
|
||||
import org.apache.dolphinscheduler.common.thread.Stopper;
|
||||
import org.apache.dolphinscheduler.common.utils.PropertyUtils;
|
||||
import org.apache.dolphinscheduler.dao.AlertDao;
|
||||
@ -35,6 +33,8 @@ import org.apache.dolphinscheduler.dao.entity.Alert;
|
||||
import org.apache.dolphinscheduler.remote.NettyRemotingServer;
|
||||
import org.apache.dolphinscheduler.remote.command.CommandType;
|
||||
import org.apache.dolphinscheduler.remote.config.NettyServerConfig;
|
||||
import org.apache.dolphinscheduler.spi.plugin.DolphinPluginLoader;
|
||||
import org.apache.dolphinscheduler.spi.plugin.DolphinPluginManagerConfig;
|
||||
import org.apache.dolphinscheduler.spi.utils.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
@ -44,45 +44,29 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
/**
|
||||
* alert of start
|
||||
*/
|
||||
public class AlertServer {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AlertServer.class);
|
||||
|
||||
/**
|
||||
* Plugin Dao
|
||||
*/
|
||||
private PluginDao pluginDao = DaoFactory.getDaoInstance(PluginDao.class);
|
||||
private final PluginDao pluginDao = DaoFactory.getDaoInstance(PluginDao.class);
|
||||
|
||||
/**
|
||||
* Alert Dao
|
||||
*/
|
||||
private AlertDao alertDao = DaoFactory.getDaoInstance(AlertDao.class);
|
||||
|
||||
private AlertSender alertSender;
|
||||
private final AlertDao alertDao = DaoFactory.getDaoInstance(AlertDao.class);
|
||||
|
||||
private AlertPluginManager alertPluginManager;
|
||||
|
||||
private DolphinPluginManagerConfig alertPluginManagerConfig;
|
||||
|
||||
public static final String ALERT_PLUGIN_BINDING = "alert.plugin.binding";
|
||||
|
||||
public static final String ALERT_PLUGIN_DIR = "alert.plugin.dir";
|
||||
|
||||
public static final String MAVEN_LOCAL_REPOSITORY = "maven.local.repository";
|
||||
|
||||
/**
|
||||
* netty server
|
||||
*/
|
||||
private NettyRemotingServer server;
|
||||
|
||||
private static class AlertServerHolder {
|
||||
private static final AlertServer INSTANCE = new AlertServer();
|
||||
}
|
||||
|
||||
public static final AlertServer getInstance() {
|
||||
public static AlertServer getInstance() {
|
||||
return AlertServerHolder.INSTANCE;
|
||||
}
|
||||
|
||||
@ -98,8 +82,7 @@ public class AlertServer {
|
||||
}
|
||||
|
||||
private void initPlugin() {
|
||||
alertPluginManager = new AlertPluginManager();
|
||||
alertPluginManagerConfig = new DolphinPluginManagerConfig();
|
||||
DolphinPluginManagerConfig alertPluginManagerConfig = new DolphinPluginManagerConfig();
|
||||
alertPluginManagerConfig.setPlugins(PropertyUtils.getString(ALERT_PLUGIN_BINDING));
|
||||
if (StringUtils.isNotBlank(PropertyUtils.getString(ALERT_PLUGIN_DIR))) {
|
||||
alertPluginManagerConfig.setInstalledPluginsDir(PropertyUtils.getString(ALERT_PLUGIN_DIR, Constants.ALERT_PLUGIN_PATH).trim());
|
||||
@ -109,6 +92,7 @@ public class AlertServer {
|
||||
alertPluginManagerConfig.setMavenLocalRepository(PropertyUtils.getString(MAVEN_LOCAL_REPOSITORY).trim());
|
||||
}
|
||||
|
||||
alertPluginManager = new AlertPluginManager();
|
||||
DolphinPluginLoader alertPluginLoader = new DolphinPluginLoader(alertPluginManagerConfig, ImmutableList.of(alertPluginManager));
|
||||
try {
|
||||
alertPluginLoader.loadPlugins();
|
||||
@ -117,9 +101,6 @@ public class AlertServer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* init netty remoting server
|
||||
*/
|
||||
private void initRemoteServer() {
|
||||
NettyServerConfig serverConfig = new NettyServerConfig();
|
||||
serverConfig.setListenPort(ALERT_RPC_PORT);
|
||||
@ -128,30 +109,10 @@ public class AlertServer {
|
||||
this.server.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cyclic alert info sending alert
|
||||
*/
|
||||
private void runSender() {
|
||||
while (Stopper.isRunning()) {
|
||||
try {
|
||||
Thread.sleep(Constants.ALERT_SCAN_INTERVAL);
|
||||
} catch (InterruptedException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
if (alertPluginManager == null || alertPluginManager.getAlertChannelMap().size() == 0) {
|
||||
logger.warn("No Alert Plugin . Cannot send alert info. ");
|
||||
} else {
|
||||
List<Alert> alerts = alertDao.listWaitExecutionAlert();
|
||||
alertSender = new AlertSender(alerts, alertDao, alertPluginManager);
|
||||
alertSender.run();
|
||||
}
|
||||
}
|
||||
new Thread(new Sender()).start();
|
||||
}
|
||||
|
||||
/**
|
||||
* start
|
||||
*/
|
||||
public void start() {
|
||||
PropertyUtils.loadPropertyFile(ALERT_PROPERTIES_PATH);
|
||||
checkTable();
|
||||
@ -161,23 +122,35 @@ public class AlertServer {
|
||||
runSender();
|
||||
}
|
||||
|
||||
/**
|
||||
* stop
|
||||
*/
|
||||
public void stop() {
|
||||
this.server.close();
|
||||
logger.info("alert server shut down");
|
||||
}
|
||||
|
||||
final class Sender implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
while (Stopper.isRunning()) {
|
||||
try {
|
||||
Thread.sleep(Constants.ALERT_SCAN_INTERVAL);
|
||||
} catch (InterruptedException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
if (alertPluginManager == null || alertPluginManager.getAlertChannelMap().size() == 0) {
|
||||
logger.warn("No Alert Plugin . Cannot send alert info. ");
|
||||
} else {
|
||||
List<Alert> alerts = alertDao.listWaitExecutionAlert();
|
||||
new AlertSender(alerts, alertDao, alertPluginManager).run();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
AlertServer alertServer = AlertServer.getInstance();
|
||||
alertServer.start();
|
||||
Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
alertServer.stop();
|
||||
}
|
||||
});
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(alertServer::stop));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ public class AlertPluginManager extends AbstractDolphinPluginManager {
|
||||
*/
|
||||
private final Map<Integer, String> pluginDefineMap = new HashMap<>();
|
||||
|
||||
private PluginDao pluginDao = DaoFactory.getDaoInstance(PluginDao.class);
|
||||
private final PluginDao pluginDao = DaoFactory.getDaoInstance(PluginDao.class);
|
||||
|
||||
private void addAlertChannelFactory(AlertChannelFactory alertChannelFactory) {
|
||||
requireNonNull(alertChannelFactory, "alertChannelFactory is null");
|
||||
|
@ -33,14 +33,11 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
|
||||
/**
|
||||
* alert request processor
|
||||
*/
|
||||
public class AlertRequestProcessor implements NettyRequestProcessor {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(AlertRequestProcessor.class);
|
||||
private AlertDao alertDao;
|
||||
private AlertPluginManager alertPluginManager;
|
||||
private final AlertDao alertDao;
|
||||
private final AlertPluginManager alertPluginManager;
|
||||
|
||||
public AlertRequestProcessor(AlertDao alertDao, AlertPluginManager alertPluginManager) {
|
||||
this.alertDao = alertDao;
|
||||
|
@ -38,16 +38,13 @@ import java.util.Map;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* alert sender
|
||||
*/
|
||||
public class AlertSender {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AlertSender.class);
|
||||
|
||||
private List<Alert> alertList;
|
||||
private AlertDao alertDao;
|
||||
private AlertPluginManager alertPluginManager;
|
||||
private final AlertPluginManager alertPluginManager;
|
||||
|
||||
public AlertSender(AlertPluginManager alertPluginManager) {
|
||||
this.alertPluginManager = alertPluginManager;
|
||||
|
@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.alert.utils;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class FuncUtilsTest {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(FuncUtilsTest.class);
|
||||
|
||||
/**
|
||||
* Test mkString
|
||||
*/
|
||||
@Test
|
||||
public void testMKString() {
|
||||
|
||||
//Define users list
|
||||
Iterable<String> users = Arrays.asList("user1", "user2", "user3");
|
||||
//Define split
|
||||
String split = "|";
|
||||
|
||||
//Invoke mkString with correctParams
|
||||
String result = FuncUtils.mkString(users, split);
|
||||
logger.info(result);
|
||||
|
||||
//Expected result string
|
||||
assertEquals("user1|user2|user3", result);
|
||||
|
||||
//Null list expected return null
|
||||
result = FuncUtils.mkString(null, split);
|
||||
assertNull(result);
|
||||
|
||||
//Null split expected return null
|
||||
result = FuncUtils.mkString(users, null);
|
||||
assertNull(result);
|
||||
|
||||
}
|
||||
}
|
@ -106,7 +106,7 @@ public class DataSourceController extends BaseController {
|
||||
@ApiOperation(value = "updateDataSource", notes = "UPDATE_DATA_SOURCE_NOTES")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "id", value = "DATA_SOURCE_ID", required = true, dataType = "Integer"),
|
||||
@ApiImplicitParam(name = "dataSourceParam", value = "DATA_SOURCE_PARAM", required = true, dataType = "BaseDataSourceParamDTO"),
|
||||
@ApiImplicitParam(name = "dataSourceParam", value = "DATA_SOURCE_PARAM", required = true, dataType = "BaseDataSourceParamDTO")
|
||||
})
|
||||
@PutMapping(value = "/{id}")
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
@ -203,7 +203,7 @@ public class DataSourceController extends BaseController {
|
||||
*/
|
||||
@ApiOperation(value = "connectDataSource", notes = "CONNECT_DATA_SOURCE_NOTES")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "dataSourceParam", value = "DATA_SOURCE_PARAM", required = true, dataType = "BaseDataSourceParamDTO"),
|
||||
@ApiImplicitParam(name = "dataSourceParam", value = "DATA_SOURCE_PARAM", required = true, dataType = "BaseDataSourceParamDTO")
|
||||
})
|
||||
@PostMapping(value = "/connect")
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
|
@ -209,6 +209,7 @@ public enum Status {
|
||||
WORKER_ADDRESS_INVALID(10177, "worker address {0} invalid", "worker地址[{0}]无效"),
|
||||
QUERY_WORKER_ADDRESS_LIST_FAIL(10178, "query worker address list fail ", "查询worker地址列表失败"),
|
||||
TRANSFORM_PROJECT_OWNERSHIP(10179, "Please transform project ownership [{0}]", "请先转移项目所有权[{0}]"),
|
||||
QUERY_ALERT_GROUP_ERROR(10180, "query alert group error", "查询告警组错误"),
|
||||
|
||||
UDF_FUNCTION_NOT_EXIST(20001, "UDF function not found", "UDF函数不存在"),
|
||||
UDF_FUNCTION_EXISTS(20002, "UDF function already exists", "UDF函数已存在"),
|
||||
|
@ -34,6 +34,14 @@ public interface AlertGroupService {
|
||||
*/
|
||||
Map<String, Object> queryAlertgroup();
|
||||
|
||||
/**
|
||||
* query alert group by id
|
||||
*
|
||||
* @param loginUser login user
|
||||
* @param id alert group id
|
||||
* @return one alert group
|
||||
*/
|
||||
Map<String, Object> queryAlertGroupById(User loginUser, Integer id);
|
||||
/**
|
||||
* paging query alarm group list
|
||||
*
|
||||
|
@ -27,6 +27,7 @@ import org.apache.dolphinscheduler.common.utils.StringUtils;
|
||||
import org.apache.dolphinscheduler.dao.entity.AlertGroup;
|
||||
import org.apache.dolphinscheduler.dao.entity.User;
|
||||
import org.apache.dolphinscheduler.dao.mapper.AlertGroupMapper;
|
||||
import org.apache.dolphinscheduler.dao.vo.AlertGroupVo;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
@ -70,6 +71,33 @@ public class AlertGroupServiceImpl extends BaseServiceImpl implements AlertGroup
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* query alert group by id
|
||||
*
|
||||
* @param loginUser login user
|
||||
* @param id alert group id
|
||||
* @return one alert group
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> queryAlertGroupById(User loginUser, Integer id) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put(Constants.STATUS, false);
|
||||
|
||||
//only admin can operate
|
||||
if (isNotAdmin(loginUser, result)) {
|
||||
return result;
|
||||
}
|
||||
//check if exist
|
||||
AlertGroup alertGroup = alertGroupMapper.selectById(id);
|
||||
if (alertGroup == null) {
|
||||
putMsg(result, Status.ALERT_GROUP_NOT_EXIST);
|
||||
return result;
|
||||
}
|
||||
result.put("data", alertGroup);
|
||||
putMsg(result, Status.SUCCESS);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* paging query alarm group list
|
||||
*
|
||||
@ -88,13 +116,14 @@ public class AlertGroupServiceImpl extends BaseServiceImpl implements AlertGroup
|
||||
return result;
|
||||
}
|
||||
|
||||
Page<AlertGroup> page = new Page<>(pageNo, pageSize);
|
||||
IPage<AlertGroup> alertGroupIPage = alertGroupMapper.queryAlertGroupPage(
|
||||
page, searchVal);
|
||||
PageInfo<AlertGroup> pageInfo = new PageInfo<>(pageNo, pageSize);
|
||||
pageInfo.setTotal((int) alertGroupIPage.getTotal());
|
||||
pageInfo.setTotalList(alertGroupIPage.getRecords());
|
||||
Page<AlertGroupVo> page = new Page<>(pageNo, pageSize);
|
||||
IPage<AlertGroupVo> alertGroupVoIPage = alertGroupMapper.queryAlertGroupVo(page, searchVal);
|
||||
PageInfo<AlertGroupVo> pageInfo = new PageInfo<>(pageNo, pageSize);
|
||||
|
||||
pageInfo.setTotal((int) alertGroupVoIPage.getTotal());
|
||||
pageInfo.setTotalList(alertGroupVoIPage.getRecords());
|
||||
result.setData(pageInfo);
|
||||
|
||||
putMsg(result, Status.SUCCESS);
|
||||
return result;
|
||||
}
|
||||
|
@ -44,8 +44,7 @@ public class CheckUtils {
|
||||
/**
|
||||
* check username
|
||||
*
|
||||
* @param userName
|
||||
* user name
|
||||
* @param userName user name
|
||||
* @return true if user name regex valid,otherwise return false
|
||||
*/
|
||||
public static boolean checkUserName(String userName) {
|
||||
@ -55,8 +54,7 @@ public class CheckUtils {
|
||||
/**
|
||||
* check email
|
||||
*
|
||||
* @param email
|
||||
* email
|
||||
* @param email email
|
||||
* @return true if email regex valid, otherwise return false
|
||||
*/
|
||||
public static boolean checkEmail(String email) {
|
||||
@ -70,8 +68,7 @@ public class CheckUtils {
|
||||
/**
|
||||
* check project description
|
||||
*
|
||||
* @param desc
|
||||
* desc
|
||||
* @param desc desc
|
||||
* @return true if description regex valid, otherwise return false
|
||||
*/
|
||||
public static Map<String, Object> checkDesc(String desc) {
|
||||
@ -79,7 +76,7 @@ public class CheckUtils {
|
||||
if (StringUtils.isNotEmpty(desc) && desc.length() > 200) {
|
||||
result.put(Constants.STATUS, Status.REQUEST_PARAMS_NOT_VALID_ERROR);
|
||||
result.put(Constants.MSG,
|
||||
MessageFormat.format(Status.REQUEST_PARAMS_NOT_VALID_ERROR.getMsg(), "desc length"));
|
||||
MessageFormat.format(Status.REQUEST_PARAMS_NOT_VALID_ERROR.getMsg(), "desc length"));
|
||||
} else {
|
||||
result.put(Constants.STATUS, Status.SUCCESS);
|
||||
}
|
||||
@ -89,8 +86,7 @@ public class CheckUtils {
|
||||
/**
|
||||
* check extra info
|
||||
*
|
||||
* @param otherParams
|
||||
* other parames
|
||||
* @param otherParams other parames
|
||||
* @return true if other parameters are valid, otherwise return false
|
||||
*/
|
||||
public static boolean checkOtherParams(String otherParams) {
|
||||
@ -100,8 +96,7 @@ public class CheckUtils {
|
||||
/**
|
||||
* check password
|
||||
*
|
||||
* @param password
|
||||
* password
|
||||
* @param password password
|
||||
* @return true if password regex valid, otherwise return false
|
||||
*/
|
||||
public static boolean checkPassword(String password) {
|
||||
@ -111,8 +106,7 @@ public class CheckUtils {
|
||||
/**
|
||||
* check phone phone can be empty.
|
||||
*
|
||||
* @param phone
|
||||
* phone
|
||||
* @param phone phone
|
||||
* @return true if phone regex valid, otherwise return false
|
||||
*/
|
||||
public static boolean checkPhone(String phone) {
|
||||
@ -122,8 +116,7 @@ public class CheckUtils {
|
||||
/**
|
||||
* check task node parameter
|
||||
*
|
||||
* @param taskNode
|
||||
* TaskNode
|
||||
* @param taskNode TaskNode
|
||||
* @return true if task node parameters are valid, otherwise return false
|
||||
*/
|
||||
public static boolean checkTaskNodeParameters(TaskNode taskNode) {
|
||||
@ -134,6 +127,8 @@ public class CheckUtils {
|
||||
}
|
||||
if (TaskType.DEPENDENT.getDesc().equalsIgnoreCase(taskType)) {
|
||||
abstractParameters = TaskParametersUtils.getParameters(taskType.toUpperCase(), taskNode.getDependence());
|
||||
} else if (TaskType.SWITCH.getDesc().equalsIgnoreCase(taskType)) {
|
||||
abstractParameters = TaskParametersUtils.getParameters(taskType.toUpperCase(), taskNode.getSwitchResult());
|
||||
} else {
|
||||
abstractParameters = TaskParametersUtils.getParameters(taskType.toUpperCase(), taskNode.getTaskParams());
|
||||
}
|
||||
@ -164,28 +159,22 @@ public class CheckUtils {
|
||||
/**
|
||||
* check params
|
||||
*
|
||||
* @param userName
|
||||
* user name
|
||||
* @param password
|
||||
* password
|
||||
* @param email
|
||||
* email
|
||||
* @param phone
|
||||
* phone
|
||||
* @param userName user name
|
||||
* @param password password
|
||||
* @param email email
|
||||
* @param phone phone
|
||||
* @return true if user parameters are valid, other return false
|
||||
*/
|
||||
public static boolean checkUserParams(String userName, String password, String email, String phone) {
|
||||
return CheckUtils.checkUserName(userName) && CheckUtils.checkEmail(email) && CheckUtils.checkPassword(password)
|
||||
&& CheckUtils.checkPhone(phone);
|
||||
&& CheckUtils.checkPhone(phone);
|
||||
}
|
||||
|
||||
/**
|
||||
* regex check
|
||||
*
|
||||
* @param str
|
||||
* input string
|
||||
* @param pattern
|
||||
* regex pattern
|
||||
* @param str input string
|
||||
* @param pattern regex pattern
|
||||
* @return true if regex pattern is right, otherwise return false
|
||||
*/
|
||||
private static boolean regexChecks(String str, Pattern pattern) {
|
||||
|
@ -47,7 +47,7 @@ public class QueueControllerTest extends AbstractControllerTest {
|
||||
@Test
|
||||
public void testQueryList() throws Exception {
|
||||
|
||||
MvcResult mvcResult = mockMvc.perform(get("/queue/list")
|
||||
MvcResult mvcResult = mockMvc.perform(get("/queues/list")
|
||||
.header(SESSION_ID, sessionId))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
|
||||
@ -66,7 +66,7 @@ public class QueueControllerTest extends AbstractControllerTest {
|
||||
paramsMap.add("pageNo","1");
|
||||
paramsMap.add("pageSize","20");
|
||||
|
||||
MvcResult mvcResult = mockMvc.perform(get("/queue/list-paging")
|
||||
MvcResult mvcResult = mockMvc.perform(get("/queues")
|
||||
.header(SESSION_ID, sessionId)
|
||||
.params(paramsMap))
|
||||
.andExpect(status().isOk())
|
||||
@ -85,7 +85,7 @@ public class QueueControllerTest extends AbstractControllerTest {
|
||||
paramsMap.add("queue", QUEUE_CREATE_STRING);
|
||||
paramsMap.add("queueName","root.queue1");
|
||||
|
||||
MvcResult mvcResult = mockMvc.perform(post("/queue/create")
|
||||
MvcResult mvcResult = mockMvc.perform(post("/queues")
|
||||
.header(SESSION_ID, sessionId)
|
||||
.params(paramsMap))
|
||||
.andExpect(status().isCreated())
|
||||
@ -104,7 +104,7 @@ public class QueueControllerTest extends AbstractControllerTest {
|
||||
paramsMap.add("queue","queue2");
|
||||
paramsMap.add("queueName","root.queue2");
|
||||
|
||||
MvcResult mvcResult = mockMvc.perform(post("/queue/update")
|
||||
MvcResult mvcResult = mockMvc.perform(post("/queues/{id}")
|
||||
.header(SESSION_ID, sessionId)
|
||||
.params(paramsMap))
|
||||
.andExpect(status().isCreated())
|
||||
@ -123,7 +123,7 @@ public class QueueControllerTest extends AbstractControllerTest {
|
||||
paramsMap.add("queue",QUEUE_CREATE_STRING);
|
||||
paramsMap.add("queueName","queue.name");
|
||||
|
||||
MvcResult mvcResult = mockMvc.perform(post("/queue/verify-queue")
|
||||
MvcResult mvcResult = mockMvc.perform(post("/queues/verify")
|
||||
.header(SESSION_ID, sessionId)
|
||||
.params(paramsMap))
|
||||
.andExpect(status().isOk())
|
||||
@ -137,7 +137,7 @@ public class QueueControllerTest extends AbstractControllerTest {
|
||||
paramsMap.add("queue","ait123");
|
||||
paramsMap.add("queueName","aitName");
|
||||
|
||||
mvcResult = mockMvc.perform(post("/queue/verify-queue")
|
||||
mvcResult = mockMvc.perform(post("/queues/verify")
|
||||
.header(SESSION_ID, sessionId)
|
||||
.params(paramsMap))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -18,6 +18,7 @@
|
||||
package org.apache.dolphinscheduler.api.controller;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.isA;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
@ -73,7 +74,7 @@ public class SchedulerControllerTest extends AbstractControllerTest {
|
||||
isA(String.class), isA(WarningType.class), isA(int.class), isA(FailureStrategy.class),
|
||||
isA(Priority.class), isA(String.class))).thenReturn(success());
|
||||
|
||||
MvcResult mvcResult = mockMvc.perform(post("/projects/{projectCode}/schedule/create",123)
|
||||
MvcResult mvcResult = mockMvc.perform(post("/projects/{projectCode}/schedules/",123)
|
||||
.header(SESSION_ID, sessionId)
|
||||
.params(paramsMap))
|
||||
.andExpect(status().isCreated())
|
||||
@ -102,7 +103,7 @@ public class SchedulerControllerTest extends AbstractControllerTest {
|
||||
isA(String.class), isA(WarningType.class), isA(Integer.class), isA(FailureStrategy.class),
|
||||
isA(Priority.class), isA(String.class))).thenReturn(success());
|
||||
|
||||
MvcResult mvcResult = mockMvc.perform(post("/projects/{projectCode}/schedule/update",123)
|
||||
MvcResult mvcResult = mockMvc.perform(post("/projects/{projectCode}/schedules/{id}",123)
|
||||
.header(SESSION_ID, sessionId)
|
||||
.params(paramsMap))
|
||||
.andExpect(status().isOk())
|
||||
@ -122,7 +123,7 @@ public class SchedulerControllerTest extends AbstractControllerTest {
|
||||
Mockito.when(schedulerService.setScheduleState(isA(User.class), isA(Long.class), isA(Integer.class),
|
||||
isA(ReleaseState.class))).thenReturn(success());
|
||||
|
||||
MvcResult mvcResult = mockMvc.perform(post("/projects/{projectCode}/schedule/online",123)
|
||||
MvcResult mvcResult = mockMvc.perform(post("/projects/{projectCode}/schedules/{id}/online",123)
|
||||
.header(SESSION_ID, sessionId)
|
||||
.params(paramsMap))
|
||||
.andExpect(status().isOk())
|
||||
@ -142,7 +143,7 @@ public class SchedulerControllerTest extends AbstractControllerTest {
|
||||
Mockito.when(schedulerService.setScheduleState(isA(User.class), isA(Long.class), isA(Integer.class),
|
||||
isA(ReleaseState.class))).thenReturn(success());
|
||||
|
||||
MvcResult mvcResult = mockMvc.perform(post("/projects/{projectCode}/schedule/offline",123)
|
||||
MvcResult mvcResult = mockMvc.perform(post("/projects/{projectCode}/schedules/{id}/offline",123)
|
||||
.header(SESSION_ID, sessionId)
|
||||
.params(paramsMap))
|
||||
.andExpect(status().isOk())
|
||||
@ -168,7 +169,7 @@ public class SchedulerControllerTest extends AbstractControllerTest {
|
||||
Mockito.when(schedulerService.querySchedule(isA(User.class), isA(Long.class), isA(Long.class),
|
||||
isA(String.class), isA(Integer.class), isA(Integer.class))).thenReturn(mockResult);
|
||||
|
||||
MvcResult mvcResult = mockMvc.perform(get("/projects/{projectCode}/schedule/list-paging",123)
|
||||
MvcResult mvcResult = mockMvc.perform(get("/projects/{projectCode}/schedules/",123)
|
||||
.header(SESSION_ID, sessionId)
|
||||
.params(paramsMap))
|
||||
.andExpect(status().isOk())
|
||||
@ -184,7 +185,7 @@ public class SchedulerControllerTest extends AbstractControllerTest {
|
||||
public void testQueryScheduleList() throws Exception {
|
||||
Mockito.when(schedulerService.queryScheduleList(isA(User.class), isA(Long.class))).thenReturn(success());
|
||||
|
||||
MvcResult mvcResult = mockMvc.perform(post("/projects/{projectCode}/schedule/list",123)
|
||||
MvcResult mvcResult = mockMvc.perform(post("/projects/{projectCode}/schedules/list",123)
|
||||
.header(SESSION_ID, sessionId))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
|
||||
@ -200,7 +201,7 @@ public class SchedulerControllerTest extends AbstractControllerTest {
|
||||
Mockito.when(schedulerService.previewSchedule(isA(User.class), isA(String.class)))
|
||||
.thenReturn(success());
|
||||
|
||||
MvcResult mvcResult = mockMvc.perform(post("/projects/{projectCode}/schedule/preview",123)
|
||||
MvcResult mvcResult = mockMvc.perform(post("/projects/{projectCode}/schedules/preview",123)
|
||||
.header(SESSION_ID, sessionId)
|
||||
.param("schedule","{'startTime':'2019-06-10 00:00:00','endTime':'2019-06-13 00:00:00','crontab':'0 0 3/6 * * ? *'}"))
|
||||
.andExpect(status().isCreated())
|
||||
@ -220,7 +221,7 @@ public class SchedulerControllerTest extends AbstractControllerTest {
|
||||
Mockito.when(schedulerService.deleteScheduleById(isA(User.class), isA(Long.class), isA(Integer.class)))
|
||||
.thenReturn(success());
|
||||
|
||||
MvcResult mvcResult = mockMvc.perform(get("/projects/{projectCode}/schedule/delete",123)
|
||||
MvcResult mvcResult = mockMvc.perform(delete("/projects/{projectCode}/schedules/{id}",123)
|
||||
.header(SESSION_ID, sessionId)
|
||||
.params(paramsMap))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
package org.apache.dolphinscheduler.api.controller;
|
||||
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
@ -49,7 +50,7 @@ public class TenantControllerTest extends AbstractControllerTest {
|
||||
paramsMap.add("queueId","1");
|
||||
paramsMap.add("description","tenant description");
|
||||
|
||||
MvcResult mvcResult = mockMvc.perform(post("/tenant/create")
|
||||
MvcResult mvcResult = mockMvc.perform(post("/tenants/")
|
||||
.header(SESSION_ID, sessionId)
|
||||
.params(paramsMap))
|
||||
.andExpect(status().isCreated())
|
||||
@ -69,7 +70,7 @@ public class TenantControllerTest extends AbstractControllerTest {
|
||||
paramsMap.add("searchVal","tenant");
|
||||
paramsMap.add("pageSize","30");
|
||||
|
||||
MvcResult mvcResult = mockMvc.perform(get("/tenant/list-paging")
|
||||
MvcResult mvcResult = mockMvc.perform(get("/tenants/")
|
||||
.header(SESSION_ID, sessionId)
|
||||
.params(paramsMap))
|
||||
.andExpect(status().isOk())
|
||||
@ -89,7 +90,7 @@ public class TenantControllerTest extends AbstractControllerTest {
|
||||
paramsMap.add("queueId","1");
|
||||
paramsMap.add("description","tenant description");
|
||||
|
||||
MvcResult mvcResult = mockMvc.perform(post("/tenant/update")
|
||||
MvcResult mvcResult = mockMvc.perform(post("/tenants/{id}")
|
||||
.header(SESSION_ID, sessionId)
|
||||
.params(paramsMap))
|
||||
.andExpect(status().isOk())
|
||||
@ -107,7 +108,7 @@ public class TenantControllerTest extends AbstractControllerTest {
|
||||
MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>();
|
||||
paramsMap.add("tenantCode","cxc_test");
|
||||
|
||||
MvcResult mvcResult = mockMvc.perform(get("/tenant/verify-tenant-code")
|
||||
MvcResult mvcResult = mockMvc.perform(get("/tenants/verify-code")
|
||||
.header(SESSION_ID, sessionId)
|
||||
.params(paramsMap))
|
||||
.andExpect(status().isOk())
|
||||
@ -125,7 +126,7 @@ public class TenantControllerTest extends AbstractControllerTest {
|
||||
MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>();
|
||||
paramsMap.add("tenantCode", "hayden");
|
||||
|
||||
MvcResult mvcResult = mockMvc.perform(get("/tenant/verify-tenant-code")
|
||||
MvcResult mvcResult = mockMvc.perform(get("/tenants/verify-code")
|
||||
.header(SESSION_ID, sessionId)
|
||||
.params(paramsMap))
|
||||
.andExpect(status().isOk())
|
||||
@ -141,7 +142,7 @@ public class TenantControllerTest extends AbstractControllerTest {
|
||||
@Test
|
||||
public void testQueryTenantlist() throws Exception {
|
||||
|
||||
MvcResult mvcResult = mockMvc.perform(get("/tenant/list")
|
||||
MvcResult mvcResult = mockMvc.perform(get("/tenants/list")
|
||||
.header(SESSION_ID, sessionId))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
|
||||
@ -158,7 +159,7 @@ public class TenantControllerTest extends AbstractControllerTest {
|
||||
MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>();
|
||||
paramsMap.add("id","64");
|
||||
|
||||
MvcResult mvcResult = mockMvc.perform(post("/tenant/delete")
|
||||
MvcResult mvcResult = mockMvc.perform(delete("/tenants/{id}")
|
||||
.header(SESSION_ID, sessionId)
|
||||
.params(paramsMap))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -30,6 +30,7 @@ import org.apache.dolphinscheduler.common.utils.CollectionUtils;
|
||||
import org.apache.dolphinscheduler.dao.entity.AlertGroup;
|
||||
import org.apache.dolphinscheduler.dao.entity.User;
|
||||
import org.apache.dolphinscheduler.dao.mapper.AlertGroupMapper;
|
||||
import org.apache.dolphinscheduler.dao.vo.AlertGroupVo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -77,10 +78,10 @@ public class AlertGroupServiceTest {
|
||||
|
||||
@Test
|
||||
public void testListPaging() {
|
||||
IPage<AlertGroup> page = new Page<>(1, 10);
|
||||
IPage<AlertGroupVo> page = new Page<>(1, 10);
|
||||
page.setTotal(1L);
|
||||
page.setRecords(getList());
|
||||
Mockito.when(alertGroupMapper.queryAlertGroupPage(any(Page.class), eq(groupName))).thenReturn(page);
|
||||
page.setRecords(getAlertGroupVoList());
|
||||
Mockito.when(alertGroupMapper.queryAlertGroupVo(any(Page.class), eq(groupName))).thenReturn(page);
|
||||
User user = new User();
|
||||
// no operate
|
||||
Result result = alertGroupService.listPaging(user, groupName, 1, 10);
|
||||
@ -90,7 +91,7 @@ public class AlertGroupServiceTest {
|
||||
user.setUserType(UserType.ADMIN_USER);
|
||||
result = alertGroupService.listPaging(user, groupName, 1, 10);
|
||||
logger.info(result.toString());
|
||||
PageInfo<AlertGroup> pageInfo = (PageInfo<AlertGroup>) result.getData();
|
||||
PageInfo<AlertGroupVo> pageInfo = (PageInfo<AlertGroupVo>) result.getData();
|
||||
Assert.assertTrue(CollectionUtils.isNotEmpty(pageInfo.getTotalList()));
|
||||
|
||||
}
|
||||
@ -216,4 +217,23 @@ public class AlertGroupServiceTest {
|
||||
return alertGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* get AlertGroupVo list
|
||||
*/
|
||||
private List<AlertGroupVo> getAlertGroupVoList() {
|
||||
List<AlertGroupVo> alertGroupVos = new ArrayList<>();
|
||||
alertGroupVos.add(getAlertGroupVoEntity());
|
||||
return alertGroupVos;
|
||||
}
|
||||
|
||||
/**
|
||||
* get AlertGroupVo entity
|
||||
*/
|
||||
private AlertGroupVo getAlertGroupVoEntity() {
|
||||
AlertGroupVo alertGroupVo = new AlertGroupVo();
|
||||
alertGroupVo.setId(1);
|
||||
alertGroupVo.setGroupName(groupName);
|
||||
return alertGroupVo;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -58,6 +58,13 @@
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>jsr305</artifactId>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@ -636,5 +643,10 @@
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
@ -435,6 +435,8 @@ public final class Constants {
|
||||
*/
|
||||
public static final String DATASOURCE_PROPERTIES = "/datasource.properties";
|
||||
|
||||
public static final String COMMON_TASK_TYPE = "common";
|
||||
|
||||
public static final String DEFAULT = "default";
|
||||
public static final String USER = "user";
|
||||
public static final String PASSWORD = "password";
|
||||
@ -781,6 +783,7 @@ public final class Constants {
|
||||
public static final String PROCESS_INSTANCE_STATE = "processInstanceState";
|
||||
public static final String PARENT_WORKFLOW_INSTANCE = "parentWorkflowInstance";
|
||||
public static final String CONDITION_RESULT = "conditionResult";
|
||||
public static final String SWITCH_RESULT = "switchResult";
|
||||
public static final String DEPENDENCE = "dependence";
|
||||
public static final String TASK_TYPE = "taskType";
|
||||
public static final String TASK_LIST = "taskList";
|
||||
@ -1013,7 +1016,7 @@ public final class Constants {
|
||||
/**
|
||||
* dataSource sensitive param
|
||||
*/
|
||||
public static final String DATASOURCE_PASSWORD_REGEX = "(?<=(\"password\":\")).*?(?=(\"))";
|
||||
public static final String DATASOURCE_PASSWORD_REGEX = "(?<=((?i)password((\\\\\":\\\\\")|(=')))).*?(?=((\\\\\")|(')))";
|
||||
|
||||
/**
|
||||
* default worker group
|
||||
|
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.common.enums;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
|
||||
/**
|
||||
* state event
|
||||
*/
|
||||
public class StateEvent {
|
||||
|
||||
/**
|
||||
* origin_pid-origin_task_id-process_instance_id-task_instance_id
|
||||
*/
|
||||
private String key;
|
||||
|
||||
private StateEventType type;
|
||||
|
||||
private ExecutionStatus executionStatus;
|
||||
|
||||
private int taskInstanceId;
|
||||
|
||||
private int processInstanceId;
|
||||
|
||||
private String context;
|
||||
|
||||
private Channel channel;
|
||||
|
||||
public ExecutionStatus getExecutionStatus() {
|
||||
return executionStatus;
|
||||
}
|
||||
|
||||
public void setExecutionStatus(ExecutionStatus executionStatus) {
|
||||
this.executionStatus = executionStatus;
|
||||
}
|
||||
|
||||
public int getTaskInstanceId() {
|
||||
return taskInstanceId;
|
||||
}
|
||||
|
||||
public int getProcessInstanceId() {
|
||||
return processInstanceId;
|
||||
}
|
||||
|
||||
public void setProcessInstanceId(int processInstanceId) {
|
||||
this.processInstanceId = processInstanceId;
|
||||
}
|
||||
|
||||
public String getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
public void setContext(String context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public void setTaskInstanceId(int taskInstanceId) {
|
||||
this.taskInstanceId = taskInstanceId;
|
||||
}
|
||||
|
||||
public Channel getChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
public void setChannel(Channel channel) {
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "State Event :"
|
||||
+ "key: " + key
|
||||
+ " type: " + type.toString()
|
||||
+ " executeStatus: " + executionStatus
|
||||
+ " task instance id: " + taskInstanceId
|
||||
+ " process instance id: " + processInstanceId
|
||||
+ " context: " + context
|
||||
;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public void setType(StateEventType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public StateEventType getType() {
|
||||
return this.type;
|
||||
}
|
||||
}
|
@ -15,33 +15,31 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.alert.utils;
|
||||
package org.apache.dolphinscheduler.common.enums;
|
||||
|
||||
import org.apache.dolphinscheduler.common.utils.StringUtils;
|
||||
import com.baomidou.mybatisplus.annotation.EnumValue;
|
||||
|
||||
public class FuncUtils {
|
||||
public enum StateEventType {
|
||||
|
||||
private FuncUtils() {
|
||||
throw new IllegalStateException(FuncUtils.class.getName());
|
||||
PROCESS_STATE_CHANGE(0, "process statechange"),
|
||||
TASK_STATE_CHANGE(1, "task state change"),
|
||||
PROCESS_TIMEOUT(2, "process timeout"),
|
||||
TASK_TIMEOUT(3, "task timeout");
|
||||
|
||||
StateEventType(int code, String descp) {
|
||||
this.code = code;
|
||||
this.descp = descp;
|
||||
}
|
||||
|
||||
public static String mkString(Iterable<String> list, String split) {
|
||||
@EnumValue
|
||||
private final int code;
|
||||
private final String descp;
|
||||
|
||||
if (null == list || StringUtils.isEmpty(split)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
boolean first = true;
|
||||
for (String item : list) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
sb.append(split);
|
||||
}
|
||||
sb.append(item);
|
||||
}
|
||||
return sb.toString();
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getDescp() {
|
||||
return descp;
|
||||
}
|
||||
}
|
@ -51,7 +51,9 @@ public enum TaskType {
|
||||
DATAX(10, "DATAX"),
|
||||
CONDITIONS(11, "CONDITIONS"),
|
||||
SQOOP(12, "SQOOP"),
|
||||
WATERDROP(13, "WATERDROP");
|
||||
WATERDROP(13, "WATERDROP"),
|
||||
SWITCH(14, "SWITCH"),
|
||||
;
|
||||
|
||||
TaskType(int code, String desc) {
|
||||
this.code = code;
|
||||
|
@ -14,6 +14,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.common.model;
|
||||
|
||||
import org.apache.dolphinscheduler.common.Constants;
|
||||
@ -33,7 +34,6 @@ import java.util.Objects;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
|
||||
|
||||
public class TaskNode {
|
||||
|
||||
/**
|
||||
@ -129,6 +129,10 @@ public class TaskNode {
|
||||
@JsonSerialize(using = JSONUtils.JsonDataSerializer.class)
|
||||
private String conditionResult;
|
||||
|
||||
@JsonDeserialize(using = JSONUtils.JsonDataDeserializer.class)
|
||||
@JsonSerialize(using = JSONUtils.JsonDataSerializer.class)
|
||||
private String switchResult;
|
||||
|
||||
/**
|
||||
* task instance priority
|
||||
*/
|
||||
@ -365,6 +369,10 @@ public class TaskNode {
|
||||
return TaskType.CONDITIONS.getDesc().equalsIgnoreCase(this.getType());
|
||||
}
|
||||
|
||||
public boolean isSwitchTask() {
|
||||
return TaskType.SWITCH.toString().equalsIgnoreCase(this.getType());
|
||||
}
|
||||
|
||||
public List<PreviousTaskNode> getPreTaskNodeList() {
|
||||
return preTaskNodeList;
|
||||
}
|
||||
@ -380,6 +388,7 @@ public class TaskNode {
|
||||
}
|
||||
taskParams.put(Constants.CONDITION_RESULT, this.conditionResult);
|
||||
taskParams.put(Constants.DEPENDENCE, this.dependence);
|
||||
taskParams.put(Constants.SWITCH_RESULT, this.switchResult);
|
||||
return JSONUtils.toJsonString(taskParams);
|
||||
}
|
||||
|
||||
@ -417,4 +426,12 @@ public class TaskNode {
|
||||
+ ", delayTime=" + delayTime
|
||||
+ '}';
|
||||
}
|
||||
|
||||
public String getSwitchResult() {
|
||||
return switchResult;
|
||||
}
|
||||
|
||||
public void setSwitchResult(String switchResult) {
|
||||
this.switchResult = switchResult;
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
|
||||
@ -152,7 +153,7 @@ public abstract class AbstractParameters implements IParameters {
|
||||
ArrayNode paramsByJson = JSONUtils.parseArray(json);
|
||||
Iterator<JsonNode> listIterator = paramsByJson.iterator();
|
||||
while (listIterator.hasNext()) {
|
||||
Map<String, String> param = JSONUtils.toMap(listIterator.next().toString(), String.class, String.class);
|
||||
Map<String, String> param = JSONUtils.parseObject(listIterator.next().toString(), new TypeReference<Map<String, String>>() {});
|
||||
allParams.add(param);
|
||||
}
|
||||
return allParams;
|
||||
|
@ -251,9 +251,9 @@ public class SqlParameters extends AbstractParameters {
|
||||
sqlResultFormat.put(key, new ArrayList<>());
|
||||
}
|
||||
for (Map<String, String> info : sqlResult) {
|
||||
for (String key : info.keySet()) {
|
||||
sqlResultFormat.get(key).add(String.valueOf(info.get(key)));
|
||||
}
|
||||
info.forEach((key, value) -> {
|
||||
sqlResultFormat.get(key).add(value);
|
||||
});
|
||||
}
|
||||
for (Property info : outProperty) {
|
||||
if (info.getType() == DataType.LIST) {
|
||||
|
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.common.task.switchtask;
|
||||
|
||||
import org.apache.dolphinscheduler.common.enums.DependentRelation;
|
||||
import org.apache.dolphinscheduler.common.process.ResourceInfo;
|
||||
import org.apache.dolphinscheduler.common.task.AbstractParameters;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SwitchParameters extends AbstractParameters {
|
||||
|
||||
private DependentRelation dependRelation;
|
||||
private String relation;
|
||||
private List<String> nextNode;
|
||||
|
||||
@Override
|
||||
public boolean checkParameters() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ResourceInfo> getResourceFilesList() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
private int resultConditionLocation;
|
||||
private List<SwitchResultVo> dependTaskList;
|
||||
|
||||
public DependentRelation getDependRelation() {
|
||||
return dependRelation;
|
||||
}
|
||||
|
||||
public void setDependRelation(DependentRelation dependRelation) {
|
||||
this.dependRelation = dependRelation;
|
||||
}
|
||||
|
||||
public int getResultConditionLocation() {
|
||||
return resultConditionLocation;
|
||||
}
|
||||
|
||||
public void setResultConditionLocation(int resultConditionLocation) {
|
||||
this.resultConditionLocation = resultConditionLocation;
|
||||
}
|
||||
|
||||
public String getRelation() {
|
||||
return relation;
|
||||
}
|
||||
|
||||
public void setRelation(String relation) {
|
||||
this.relation = relation;
|
||||
}
|
||||
|
||||
public List<SwitchResultVo> getDependTaskList() {
|
||||
return dependTaskList;
|
||||
}
|
||||
|
||||
public void setDependTaskList(List<SwitchResultVo> dependTaskList) {
|
||||
this.dependTaskList = dependTaskList;
|
||||
}
|
||||
|
||||
public List<String> getNextNode() {
|
||||
return nextNode;
|
||||
}
|
||||
|
||||
public void setNextNode(Object nextNode) {
|
||||
if (nextNode instanceof String) {
|
||||
List<String> nextNodeList = new ArrayList<>();
|
||||
nextNodeList.add(String.valueOf(nextNode));
|
||||
this.nextNode = nextNodeList;
|
||||
} else {
|
||||
this.nextNode = (ArrayList) nextNode;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.common.task.switchtask;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SwitchResultVo {
|
||||
|
||||
private String condition;
|
||||
private List<String> nextNode;
|
||||
|
||||
public String getCondition() {
|
||||
return condition;
|
||||
}
|
||||
|
||||
public void setCondition(String condition) {
|
||||
this.condition = condition;
|
||||
}
|
||||
|
||||
public List<String> getNextNode() {
|
||||
return nextNode;
|
||||
}
|
||||
|
||||
public void setNextNode(Object nextNode) {
|
||||
if (nextNode instanceof String) {
|
||||
List<String> nextNodeList = new ArrayList<>();
|
||||
nextNodeList.add(String.valueOf(nextNode));
|
||||
this.nextNode = nextNodeList;
|
||||
} else {
|
||||
this.nextNode = (ArrayList) nextNode;
|
||||
}
|
||||
}
|
||||
}
|
@ -31,6 +31,7 @@ import org.apache.dolphinscheduler.common.task.spark.SparkParameters;
|
||||
import org.apache.dolphinscheduler.common.task.sql.SqlParameters;
|
||||
import org.apache.dolphinscheduler.common.task.sqoop.SqoopParameters;
|
||||
import org.apache.dolphinscheduler.common.task.subprocess.SubProcessParameters;
|
||||
import org.apache.dolphinscheduler.common.task.switchtask.SwitchParameters;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -82,6 +83,8 @@ public class TaskParametersUtils {
|
||||
return JSONUtils.parseObject(parameter, ConditionsParameters.class);
|
||||
case "SQOOP":
|
||||
return JSONUtils.parseObject(parameter, SqoopParameters.class);
|
||||
case "SWITCH":
|
||||
return JSONUtils.parseObject(parameter, SwitchParameters.class);
|
||||
default:
|
||||
logger.error("not support task type: {}", taskType);
|
||||
return null;
|
||||
|
@ -23,6 +23,7 @@ import org.apache.dolphinscheduler.common.enums.Flag;
|
||||
import org.apache.dolphinscheduler.common.enums.Priority;
|
||||
import org.apache.dolphinscheduler.common.enums.TaskType;
|
||||
import org.apache.dolphinscheduler.common.task.dependent.DependentParameters;
|
||||
import org.apache.dolphinscheduler.common.task.switchtask.SwitchParameters;
|
||||
import org.apache.dolphinscheduler.common.utils.JSONUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
@ -174,6 +175,12 @@ public class TaskInstance implements Serializable {
|
||||
@TableField(exist = false)
|
||||
private DependentParameters dependency;
|
||||
|
||||
/**
|
||||
* switch dependency
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private SwitchParameters switchDependency;
|
||||
|
||||
/**
|
||||
* duration
|
||||
*/
|
||||
@ -426,6 +433,20 @@ public class TaskInstance implements Serializable {
|
||||
this.dependency = dependency;
|
||||
}
|
||||
|
||||
public SwitchParameters getSwitchDependency() {
|
||||
if (this.switchDependency == null) {
|
||||
Map<String, Object> taskParamsMap = JSONUtils.toMap(this.getTaskParams(), String.class, Object.class);
|
||||
this.switchDependency = JSONUtils.parseObject((String) taskParamsMap.get(Constants.SWITCH_RESULT), SwitchParameters.class);
|
||||
}
|
||||
return this.switchDependency;
|
||||
}
|
||||
|
||||
public void setSwitchDependency(SwitchParameters switchDependency) {
|
||||
Map<String, Object> taskParamsMap = JSONUtils.toMap(this.getTaskParams(), String.class, Object.class);
|
||||
taskParamsMap.put(Constants.SWITCH_RESULT,JSONUtils.toJsonString(switchDependency));
|
||||
this.setTaskParams(JSONUtils.toJsonString(taskParamsMap));
|
||||
}
|
||||
|
||||
public Flag getFlag() {
|
||||
return flag;
|
||||
}
|
||||
@ -510,6 +531,10 @@ public class TaskInstance implements Serializable {
|
||||
return TaskType.CONDITIONS.getDesc().equalsIgnoreCase(this.taskType);
|
||||
}
|
||||
|
||||
public boolean isSwitchTask() {
|
||||
return TaskType.SWITCH.getDesc().equalsIgnoreCase(this.taskType);
|
||||
}
|
||||
|
||||
/**
|
||||
* determine if you can try again
|
||||
*
|
||||
|
@ -18,6 +18,7 @@
|
||||
package org.apache.dolphinscheduler.dao.mapper;
|
||||
|
||||
import org.apache.dolphinscheduler.dao.entity.AlertGroup;
|
||||
import org.apache.dolphinscheduler.dao.vo.AlertGroupVo;
|
||||
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
@ -82,4 +83,13 @@ public interface AlertGroupMapper extends BaseMapper<AlertGroup> {
|
||||
* @return
|
||||
*/
|
||||
String queryAlertGroupInstanceIdsById(@Param("alertGroupId") int alertGroupId);
|
||||
|
||||
/**
|
||||
* query alertGroupVo page list
|
||||
* @param page page
|
||||
* @param groupName groupName
|
||||
* @return IPage<AlertGroupVo>: include alert group id and group_name
|
||||
*/
|
||||
IPage<AlertGroupVo> queryAlertGroupVo(Page<AlertGroupVo> page,
|
||||
@Param("groupName") String groupName);
|
||||
}
|
||||
|
@ -17,6 +17,8 @@
|
||||
package org.apache.dolphinscheduler.dao.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
|
||||
import org.apache.dolphinscheduler.dao.entity.Command;
|
||||
import org.apache.dolphinscheduler.dao.entity.CommandCount;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
@ -50,6 +52,10 @@ public interface CommandMapper extends BaseMapper<Command> {
|
||||
@Param("endTime") Date endTime,
|
||||
@Param("projectCodeArray") Long[] projectCodeArray);
|
||||
|
||||
|
||||
/**
|
||||
* query command page
|
||||
* @return
|
||||
*/
|
||||
IPage<Command> queryCommandPage(IPage<Command> page);
|
||||
|
||||
}
|
||||
|
@ -14,8 +14,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dolphinscheduler.dao.utils;
|
||||
|
||||
package org.apache.dolphinscheduler.dao.utils;
|
||||
|
||||
import org.apache.dolphinscheduler.common.enums.TaskDependType;
|
||||
import org.apache.dolphinscheduler.common.graph.DAG;
|
||||
@ -23,6 +23,8 @@ import org.apache.dolphinscheduler.common.model.TaskNode;
|
||||
import org.apache.dolphinscheduler.common.model.TaskNodeRelation;
|
||||
import org.apache.dolphinscheduler.common.process.ProcessDag;
|
||||
import org.apache.dolphinscheduler.common.task.conditions.ConditionsParameters;
|
||||
import org.apache.dolphinscheduler.common.task.switchtask.SwitchParameters;
|
||||
import org.apache.dolphinscheduler.common.task.switchtask.SwitchResultVo;
|
||||
import org.apache.dolphinscheduler.common.utils.CollectionUtils;
|
||||
import org.apache.dolphinscheduler.common.utils.JSONUtils;
|
||||
import org.apache.dolphinscheduler.dao.entity.ProcessTaskRelation;
|
||||
@ -281,6 +283,9 @@ public class DagHelper {
|
||||
} else if (dag.getNode(preNodeName).isConditionsTask()) {
|
||||
List<String> conditionTaskList = parseConditionTask(preNodeName, skipTaskNodeList, dag, completeTaskList);
|
||||
startVertexes.addAll(conditionTaskList);
|
||||
} else if (dag.getNode(preNodeName).isSwitchTask()) {
|
||||
List<String> conditionTaskList = parseSwitchTask(preNodeName, skipTaskNodeList, dag, completeTaskList);
|
||||
startVertexes.addAll(conditionTaskList);
|
||||
} else {
|
||||
startVertexes = dag.getSubsequentNodes(preNodeName);
|
||||
}
|
||||
@ -355,6 +360,49 @@ public class DagHelper {
|
||||
return conditionTaskList;
|
||||
}
|
||||
|
||||
/**
|
||||
* parse condition task find the branch process
|
||||
* set skip flag for another one.
|
||||
*
|
||||
* @param nodeName
|
||||
* @return
|
||||
*/
|
||||
public static List<String> parseSwitchTask(String nodeName,
|
||||
Map<String, TaskNode> skipTaskNodeList,
|
||||
DAG<String, TaskNode, TaskNodeRelation> dag,
|
||||
Map<String, TaskInstance> completeTaskList) {
|
||||
List<String> conditionTaskList = new ArrayList<>();
|
||||
TaskNode taskNode = dag.getNode(nodeName);
|
||||
if (!taskNode.isSwitchTask()) {
|
||||
return conditionTaskList;
|
||||
}
|
||||
if (!completeTaskList.containsKey(nodeName)) {
|
||||
return conditionTaskList;
|
||||
}
|
||||
conditionTaskList = skipTaskNode4Switch(taskNode, skipTaskNodeList, completeTaskList, dag);
|
||||
return conditionTaskList;
|
||||
}
|
||||
|
||||
private static List<String> skipTaskNode4Switch(TaskNode taskNode, Map<String, TaskNode> skipTaskNodeList,
|
||||
Map<String, TaskInstance> completeTaskList,
|
||||
DAG<String, TaskNode, TaskNodeRelation> dag) {
|
||||
SwitchParameters switchParameters = completeTaskList.get(taskNode.getName()).getSwitchDependency();
|
||||
int resultConditionLocation = switchParameters.getResultConditionLocation();
|
||||
List<SwitchResultVo> conditionResultVoList = switchParameters.getDependTaskList();
|
||||
List<String> switchTaskList = conditionResultVoList.get(resultConditionLocation).getNextNode();
|
||||
if (CollectionUtils.isEmpty(switchTaskList)) {
|
||||
switchTaskList = new ArrayList<>();
|
||||
}
|
||||
conditionResultVoList.remove(resultConditionLocation);
|
||||
for (SwitchResultVo info : conditionResultVoList) {
|
||||
if (CollectionUtils.isEmpty(info.getNextNode())) {
|
||||
continue;
|
||||
}
|
||||
setTaskNodeSkip(info.getNextNode().get(0), dag, completeTaskList, skipTaskNodeList);
|
||||
}
|
||||
return switchTaskList;
|
||||
}
|
||||
|
||||
/**
|
||||
* set task node and the post nodes skip flag
|
||||
*/
|
||||
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.dao.vo;
|
||||
|
||||
/**
|
||||
* AlertGroupVo
|
||||
*/
|
||||
public class AlertGroupVo {
|
||||
|
||||
/**
|
||||
* primary key
|
||||
*/
|
||||
private int id;
|
||||
/**
|
||||
* group_name
|
||||
*/
|
||||
private String groupName;
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getGroupName() {
|
||||
return groupName;
|
||||
}
|
||||
|
||||
public void setGroupName(String groupName) {
|
||||
this.groupName = groupName;
|
||||
}
|
||||
|
||||
}
|
@ -32,6 +32,15 @@
|
||||
</if>
|
||||
order by update_time desc
|
||||
</select>
|
||||
<select id="queryAlertGroupVo" resultType="org.apache.dolphinscheduler.dao.vo.AlertGroupVo">
|
||||
select id, group_name
|
||||
from t_ds_alertgroup
|
||||
where 1 = 1
|
||||
<if test="groupName != null and groupName != ''">
|
||||
and group_name like concat('%', #{groupName}, '%')
|
||||
</if>
|
||||
order by update_time desc
|
||||
</select>
|
||||
<select id="queryByGroupName" resultType="org.apache.dolphinscheduler.dao.entity.AlertGroup">
|
||||
select
|
||||
<include refid="baseSql"/>
|
||||
@ -70,4 +79,4 @@
|
||||
select alert_instance_ids from t_ds_alertgroup
|
||||
where id = #{alertGroupId}
|
||||
</select>
|
||||
</mapper>
|
||||
</mapper>
|
||||
|
@ -43,4 +43,9 @@
|
||||
</if>
|
||||
group by cmd.command_type
|
||||
</select>
|
||||
<select id="queryCommandPage" resultType="org.apache.dolphinscheduler.dao.entity.Command">
|
||||
select *
|
||||
from t_ds_command
|
||||
order by update_time asc
|
||||
</select>
|
||||
</mapper>
|
||||
|
@ -46,4 +46,4 @@
|
||||
where id = #{id}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
</mapper>
|
||||
|
@ -25,6 +25,8 @@ import org.apache.dolphinscheduler.common.graph.DAG;
|
||||
import org.apache.dolphinscheduler.common.model.TaskNode;
|
||||
import org.apache.dolphinscheduler.common.model.TaskNodeRelation;
|
||||
import org.apache.dolphinscheduler.common.process.ProcessDag;
|
||||
import org.apache.dolphinscheduler.common.task.switchtask.SwitchParameters;
|
||||
import org.apache.dolphinscheduler.common.task.switchtask.SwitchResultVo;
|
||||
import org.apache.dolphinscheduler.common.utils.JSONUtils;
|
||||
import org.apache.dolphinscheduler.dao.entity.ProcessData;
|
||||
import org.apache.dolphinscheduler.dao.entity.TaskInstance;
|
||||
@ -251,6 +253,10 @@ public class DagHelperTest {
|
||||
skipNodeList.clear();
|
||||
completeTaskList.remove("3");
|
||||
taskInstance = new TaskInstance();
|
||||
|
||||
Map<String, Object> taskParamsMap = new HashMap<>();
|
||||
taskParamsMap.put(Constants.SWITCH_RESULT, "");
|
||||
taskInstance.setTaskParams(JSONUtils.toJsonString(taskParamsMap));
|
||||
taskInstance.setState(ExecutionStatus.FAILURE);
|
||||
completeTaskList.put("3", taskInstance);
|
||||
postNodes = DagHelper.parsePostNodes(null, skipNodeList, dag, completeTaskList);
|
||||
@ -259,6 +265,17 @@ public class DagHelperTest {
|
||||
Assert.assertEquals(2, skipNodeList.size());
|
||||
Assert.assertTrue(skipNodeList.containsKey("5"));
|
||||
Assert.assertTrue(skipNodeList.containsKey("7"));
|
||||
|
||||
// dag: 1-2-3-5-7 4-3-6
|
||||
// 3-if , complete:1/2/3/4
|
||||
// 1.failure:3 expect post:6 skip:5/7
|
||||
dag = generateDag2();
|
||||
skipNodeList.clear();
|
||||
completeTaskList.clear();
|
||||
taskInstance.setSwitchDependency(getSwitchNode());
|
||||
completeTaskList.put("1", taskInstance);
|
||||
postNodes = DagHelper.parsePostNodes("1", skipNodeList, dag, completeTaskList);
|
||||
Assert.assertEquals(1, postNodes.size());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -286,7 +303,6 @@ public class DagHelperTest {
|
||||
node2.setPreTasks(JSONUtils.toJsonString(dep2));
|
||||
taskNodeList.add(node2);
|
||||
|
||||
|
||||
TaskNode node4 = new TaskNode();
|
||||
node4.setId("4");
|
||||
node4.setName("4");
|
||||
@ -351,6 +367,87 @@ public class DagHelperTest {
|
||||
return DagHelper.buildDagGraph(processDag);
|
||||
}
|
||||
|
||||
/**
|
||||
* 1->2->3->5->7
|
||||
* 4->3->6
|
||||
* 2->8->5->7
|
||||
*
|
||||
* @return dag
|
||||
* @throws JsonProcessingException if error throws JsonProcessingException
|
||||
*/
|
||||
private DAG<String, TaskNode, TaskNodeRelation> generateDag2() throws IOException {
|
||||
List<TaskNode> taskNodeList = new ArrayList<>();
|
||||
|
||||
TaskNode node = new TaskNode();
|
||||
node.setId("0");
|
||||
node.setName("0");
|
||||
node.setType("SHELL");
|
||||
taskNodeList.add(node);
|
||||
|
||||
TaskNode node1 = new TaskNode();
|
||||
node1.setId("1");
|
||||
node1.setName("1");
|
||||
node1.setType("switch");
|
||||
node1.setDependence(JSONUtils.toJsonString(getSwitchNode()));
|
||||
taskNodeList.add(node1);
|
||||
|
||||
TaskNode node2 = new TaskNode();
|
||||
node2.setId("2");
|
||||
node2.setName("2");
|
||||
node2.setType("SHELL");
|
||||
List<String> dep2 = new ArrayList<>();
|
||||
dep2.add("1");
|
||||
node2.setPreTasks(JSONUtils.toJsonString(dep2));
|
||||
taskNodeList.add(node2);
|
||||
|
||||
TaskNode node4 = new TaskNode();
|
||||
node4.setId("4");
|
||||
node4.setName("4");
|
||||
node4.setType("SHELL");
|
||||
List<String> dep4 = new ArrayList<>();
|
||||
dep4.add("1");
|
||||
node4.setPreTasks(JSONUtils.toJsonString(dep4));
|
||||
taskNodeList.add(node4);
|
||||
|
||||
TaskNode node5 = new TaskNode();
|
||||
node5.setId("4");
|
||||
node5.setName("4");
|
||||
node5.setType("SHELL");
|
||||
List<String> dep5 = new ArrayList<>();
|
||||
dep5.add("1");
|
||||
node5.setPreTasks(JSONUtils.toJsonString(dep5));
|
||||
taskNodeList.add(node5);
|
||||
|
||||
List<String> startNodes = new ArrayList<>();
|
||||
List<String> recoveryNodes = new ArrayList<>();
|
||||
List<TaskNode> destTaskNodeList = DagHelper.generateFlowNodeListByStartNode(taskNodeList,
|
||||
startNodes, recoveryNodes, TaskDependType.TASK_POST);
|
||||
List<TaskNodeRelation> taskNodeRelations = DagHelper.generateRelationListByFlowNodes(destTaskNodeList);
|
||||
ProcessDag processDag = new ProcessDag();
|
||||
processDag.setEdges(taskNodeRelations);
|
||||
processDag.setNodes(destTaskNodeList);
|
||||
return DagHelper.buildDagGraph(processDag);
|
||||
}
|
||||
|
||||
private SwitchParameters getSwitchNode() {
|
||||
SwitchParameters conditionsParameters = new SwitchParameters();
|
||||
SwitchResultVo switchResultVo1 = new SwitchResultVo();
|
||||
switchResultVo1.setCondition(" 2 == 1");
|
||||
switchResultVo1.setNextNode("2");
|
||||
SwitchResultVo switchResultVo2 = new SwitchResultVo();
|
||||
switchResultVo2.setCondition(" 2 == 2");
|
||||
switchResultVo2.setNextNode("4");
|
||||
List<SwitchResultVo> list = new ArrayList<>();
|
||||
list.add(switchResultVo1);
|
||||
list.add(switchResultVo2);
|
||||
conditionsParameters.setDependTaskList(list);
|
||||
conditionsParameters.setNextNode("5");
|
||||
conditionsParameters.setRelation("AND");
|
||||
|
||||
// in: AND(AND(1 is SUCCESS))
|
||||
return conditionsParameters;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuildDagGraph() {
|
||||
String shellJson = "{\"globalParams\":[],\"tasks\":[{\"type\":\"SHELL\",\"id\":\"tasks-9527\",\"name\":\"shell-1\","
|
||||
|
@ -61,15 +61,6 @@
|
||||
<outputDirectory>conf</outputDirectory>
|
||||
</fileSet>
|
||||
|
||||
<fileSet>
|
||||
<directory>${basedir}/../dolphinscheduler-common/src/main/resources/bin</directory>
|
||||
<includes>
|
||||
<include>*.*</include>
|
||||
</includes>
|
||||
<directoryMode>755</directoryMode>
|
||||
<outputDirectory>bin</outputDirectory>
|
||||
</fileSet>
|
||||
|
||||
<fileSet>
|
||||
<directory>${basedir}/../dolphinscheduler-dao/src/main/resources</directory>
|
||||
<includes>
|
||||
|
@ -47,6 +47,7 @@ import org.apache.curator.framework.recipes.locks.InterProcessMutex;
|
||||
import org.apache.curator.retry.ExponentialBackoffRetry;
|
||||
import org.apache.curator.utils.CloseableUtils;
|
||||
import org.apache.zookeeper.CreateMode;
|
||||
import org.apache.zookeeper.KeeperException;
|
||||
import org.apache.zookeeper.ZooDefs;
|
||||
import org.apache.zookeeper.data.ACL;
|
||||
|
||||
@ -195,12 +196,7 @@ public class ZookeeperRegistry implements Registry {
|
||||
|
||||
@Override
|
||||
public void remove(String key) {
|
||||
|
||||
try {
|
||||
client.delete().deletingChildrenIfNeeded().forPath(key);
|
||||
} catch (Exception e) {
|
||||
throw new RegistryException("zookeeper remove error", e);
|
||||
}
|
||||
delete(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -269,6 +265,9 @@ public class ZookeeperRegistry implements Registry {
|
||||
client.delete()
|
||||
.deletingChildrenIfNeeded()
|
||||
.forPath(nodePath);
|
||||
} catch (KeeperException.NoNodeException ignore) {
|
||||
// the node is not exist, we can believe the node has been removed
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RegistryException("zookeeper delete key error", e);
|
||||
}
|
||||
|
@ -83,6 +83,16 @@
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>jsr305</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
@ -30,12 +30,12 @@ public enum CommandType {
|
||||
REMOVE_TAK_LOG_RESPONSE,
|
||||
|
||||
/**
|
||||
* roll view log request
|
||||
* roll view log request
|
||||
*/
|
||||
ROLL_VIEW_LOG_REQUEST,
|
||||
|
||||
/**
|
||||
* roll view log response
|
||||
* roll view log response
|
||||
*/
|
||||
ROLL_VIEW_LOG_RESPONSE,
|
||||
|
||||
@ -109,17 +109,32 @@ public enum CommandType {
|
||||
PING,
|
||||
|
||||
/**
|
||||
* pong
|
||||
* pong
|
||||
*/
|
||||
PONG,
|
||||
|
||||
/**
|
||||
* alert send request
|
||||
* alert send request
|
||||
*/
|
||||
ALERT_SEND_REQUEST,
|
||||
|
||||
/**
|
||||
* alert send response
|
||||
* alert send response
|
||||
*/
|
||||
ALERT_SEND_RESPONSE;
|
||||
ALERT_SEND_RESPONSE,
|
||||
|
||||
/**
|
||||
* process host update
|
||||
*/
|
||||
PROCESS_HOST_UPDATE_REQUST,
|
||||
|
||||
/**
|
||||
* process host update response
|
||||
*/
|
||||
PROCESS_HOST_UPDATE_RESPONSE,
|
||||
|
||||
/**
|
||||
* state event request
|
||||
*/
|
||||
STATE_EVENT_REQUEST;
|
||||
}
|
||||
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.remote.command;
|
||||
|
||||
import org.apache.dolphinscheduler.common.utils.JSONUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* process host update
|
||||
*/
|
||||
public class HostUpdateCommand implements Serializable {
|
||||
|
||||
/**
|
||||
* task id
|
||||
*/
|
||||
private int taskInstanceId;
|
||||
|
||||
private String processHost;
|
||||
|
||||
public int getTaskInstanceId() {
|
||||
return taskInstanceId;
|
||||
}
|
||||
|
||||
public void setTaskInstanceId(int taskInstanceId) {
|
||||
this.taskInstanceId = taskInstanceId;
|
||||
}
|
||||
|
||||
public String getProcessHost() {
|
||||
return processHost;
|
||||
}
|
||||
|
||||
public void setProcessHost(String processHost) {
|
||||
this.processHost = processHost;
|
||||
}
|
||||
|
||||
/**
|
||||
* package request command
|
||||
*
|
||||
* @return command
|
||||
*/
|
||||
public Command convert2Command() {
|
||||
Command command = new Command();
|
||||
command.setType(CommandType.PROCESS_HOST_UPDATE_REQUST);
|
||||
byte[] body = JSONUtils.toJsonByteArray(this);
|
||||
command.setBody(body);
|
||||
return command;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HostUpdateCommand{"
|
||||
+ "taskInstanceId=" + taskInstanceId
|
||||
+ "host=" + processHost
|
||||
+ '}';
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.remote.command;
|
||||
|
||||
import org.apache.dolphinscheduler.common.utils.JSONUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class HostUpdateResponseCommand implements Serializable {
|
||||
|
||||
private int taskInstanceId;
|
||||
|
||||
private String processHost;
|
||||
|
||||
private int status;
|
||||
|
||||
public HostUpdateResponseCommand(int taskInstanceId, String processHost, int code) {
|
||||
this.taskInstanceId = taskInstanceId;
|
||||
this.processHost = processHost;
|
||||
this.status = code;
|
||||
}
|
||||
|
||||
public int getTaskInstanceId() {
|
||||
return this.taskInstanceId;
|
||||
}
|
||||
|
||||
public void setTaskInstanceId(int taskInstanceId) {
|
||||
this.taskInstanceId = taskInstanceId;
|
||||
}
|
||||
|
||||
public String getProcessHost() {
|
||||
return this.processHost;
|
||||
}
|
||||
|
||||
public void setProcessHost(String processHost) {
|
||||
this.processHost = processHost;
|
||||
}
|
||||
|
||||
public int getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(int status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* package request command
|
||||
*
|
||||
* @return command
|
||||
*/
|
||||
public Command convert2Command() {
|
||||
Command command = new Command();
|
||||
command.setType(CommandType.PROCESS_HOST_UPDATE_REQUST);
|
||||
byte[] body = JSONUtils.toJsonByteArray(this);
|
||||
command.setBody(body);
|
||||
return command;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HostUpdateResponseCommand{"
|
||||
+ "taskInstanceId=" + taskInstanceId
|
||||
+ "host=" + processHost
|
||||
+ '}';
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.remote.command;
|
||||
|
||||
import org.apache.dolphinscheduler.common.enums.ExecutionStatus;
|
||||
import org.apache.dolphinscheduler.common.utils.JSONUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* db task final result response command
|
||||
*/
|
||||
public class StateEventChangeCommand implements Serializable {
|
||||
|
||||
private String key;
|
||||
|
||||
private ExecutionStatus sourceStatus;
|
||||
|
||||
private int sourceProcessInstanceId;
|
||||
|
||||
private int sourceTaskInstanceId;
|
||||
|
||||
private int destProcessInstanceId;
|
||||
|
||||
private int destTaskInstanceId;
|
||||
|
||||
public StateEventChangeCommand() {
|
||||
super();
|
||||
}
|
||||
|
||||
public StateEventChangeCommand(int sourceProcessInstanceId, int sourceTaskInstanceId,
|
||||
ExecutionStatus sourceStatus,
|
||||
int destProcessInstanceId,
|
||||
int destTaskInstanceId
|
||||
) {
|
||||
this.key = String.format("%d-%d-%d-%d",
|
||||
sourceProcessInstanceId,
|
||||
sourceTaskInstanceId,
|
||||
destProcessInstanceId,
|
||||
destTaskInstanceId);
|
||||
|
||||
this.sourceStatus = sourceStatus;
|
||||
this.sourceProcessInstanceId = sourceProcessInstanceId;
|
||||
this.sourceTaskInstanceId = sourceTaskInstanceId;
|
||||
this.destProcessInstanceId = destProcessInstanceId;
|
||||
this.destTaskInstanceId = destTaskInstanceId;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* package response command
|
||||
*
|
||||
* @return command
|
||||
*/
|
||||
public Command convert2Command() {
|
||||
Command command = new Command();
|
||||
command.setType(CommandType.STATE_EVENT_REQUEST);
|
||||
byte[] body = JSONUtils.toJsonByteArray(this);
|
||||
command.setBody(body);
|
||||
return command;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "StateEventResponseCommand{"
|
||||
+ "key=" + key
|
||||
+ '}';
|
||||
}
|
||||
|
||||
public ExecutionStatus getSourceStatus() {
|
||||
return sourceStatus;
|
||||
}
|
||||
|
||||
public void setSourceStatus(ExecutionStatus sourceStatus) {
|
||||
this.sourceStatus = sourceStatus;
|
||||
}
|
||||
|
||||
public int getSourceProcessInstanceId() {
|
||||
return sourceProcessInstanceId;
|
||||
}
|
||||
|
||||
public void setSourceProcessInstanceId(int sourceProcessInstanceId) {
|
||||
this.sourceProcessInstanceId = sourceProcessInstanceId;
|
||||
}
|
||||
|
||||
public int getSourceTaskInstanceId() {
|
||||
return sourceTaskInstanceId;
|
||||
}
|
||||
|
||||
public void setSourceTaskInstanceId(int sourceTaskInstanceId) {
|
||||
this.sourceTaskInstanceId = sourceTaskInstanceId;
|
||||
}
|
||||
|
||||
public int getDestProcessInstanceId() {
|
||||
return destProcessInstanceId;
|
||||
}
|
||||
|
||||
public void setDestProcessInstanceId(int destProcessInstanceId) {
|
||||
this.destProcessInstanceId = destProcessInstanceId;
|
||||
}
|
||||
|
||||
public int getDestTaskInstanceId() {
|
||||
return destTaskInstanceId;
|
||||
}
|
||||
|
||||
public void setDestTaskInstanceId(int destTaskInstanceId) {
|
||||
this.destTaskInstanceId = destTaskInstanceId;
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.remote.command;
|
||||
|
||||
import org.apache.dolphinscheduler.common.utils.JSONUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* db task final result response command
|
||||
*/
|
||||
public class StateEventResponseCommand implements Serializable {
|
||||
|
||||
private String key;
|
||||
private int status;
|
||||
|
||||
public StateEventResponseCommand() {
|
||||
super();
|
||||
}
|
||||
|
||||
public StateEventResponseCommand(int status, String key) {
|
||||
this.status = status;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public int getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(int status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* package response command
|
||||
*
|
||||
* @return command
|
||||
*/
|
||||
public Command convert2Command() {
|
||||
Command command = new Command();
|
||||
command.setType(CommandType.DB_TASK_RESPONSE);
|
||||
byte[] body = JSONUtils.toJsonByteArray(this);
|
||||
command.setBody(body);
|
||||
return command;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "StateEventResponseCommand{"
|
||||
+ "key=" + key
|
||||
+ ", status=" + status
|
||||
+ '}';
|
||||
}
|
||||
|
||||
}
|
@ -25,7 +25,7 @@ import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
/**
|
||||
* execute task request command
|
||||
* execute task request command
|
||||
*/
|
||||
public class TaskExecuteAckCommand implements Serializable {
|
||||
|
||||
@ -34,10 +34,15 @@ public class TaskExecuteAckCommand implements Serializable {
|
||||
*/
|
||||
private int taskInstanceId;
|
||||
|
||||
/**
|
||||
* process instance id
|
||||
*/
|
||||
private int processInstanceId;
|
||||
|
||||
/**
|
||||
* startTime
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date startTime;
|
||||
|
||||
/**
|
||||
@ -109,7 +114,7 @@ public class TaskExecuteAckCommand implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* package request command
|
||||
* package request command
|
||||
*
|
||||
* @return command
|
||||
*/
|
||||
@ -130,6 +135,15 @@ public class TaskExecuteAckCommand implements Serializable {
|
||||
+ ", status=" + status
|
||||
+ ", logPath='" + logPath + '\''
|
||||
+ ", executePath='" + executePath + '\''
|
||||
+ ", processInstanceId='" + processInstanceId + '\''
|
||||
+ '}';
|
||||
}
|
||||
|
||||
public int getProcessInstanceId() {
|
||||
return processInstanceId;
|
||||
}
|
||||
|
||||
public void setProcessInstanceId(int processInstanceId) {
|
||||
this.processInstanceId = processInstanceId;
|
||||
}
|
||||
}
|
||||
|
@ -32,8 +32,9 @@ public class TaskExecuteResponseCommand implements Serializable {
|
||||
public TaskExecuteResponseCommand() {
|
||||
}
|
||||
|
||||
public TaskExecuteResponseCommand(int taskInstanceId) {
|
||||
public TaskExecuteResponseCommand(int taskInstanceId, int processInstanceId) {
|
||||
this.taskInstanceId = taskInstanceId;
|
||||
this.processInstanceId = processInstanceId;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -41,6 +42,11 @@ public class TaskExecuteResponseCommand implements Serializable {
|
||||
*/
|
||||
private int taskInstanceId;
|
||||
|
||||
/**
|
||||
* process instance id
|
||||
*/
|
||||
private int processInstanceId;
|
||||
|
||||
/**
|
||||
* status
|
||||
*/
|
||||
@ -139,4 +145,12 @@ public class TaskExecuteResponseCommand implements Serializable {
|
||||
+ ", appIds='" + appIds + '\''
|
||||
+ '}';
|
||||
}
|
||||
|
||||
public int getProcessInstanceId() {
|
||||
return processInstanceId;
|
||||
}
|
||||
|
||||
public void setProcessInstanceId(int processInstanceId) {
|
||||
this.processInstanceId = processInstanceId;
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.server.worker.processor;
|
||||
package org.apache.dolphinscheduler.remote.processor;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFuture;
|
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.remote.processor;
|
||||
|
||||
import static org.apache.dolphinscheduler.common.Constants.SLEEP_TIME_MILLIS;
|
||||
|
||||
import org.apache.dolphinscheduler.remote.NettyRemotingClient;
|
||||
import org.apache.dolphinscheduler.remote.command.Command;
|
||||
import org.apache.dolphinscheduler.remote.config.NettyClientConfig;
|
||||
import org.apache.dolphinscheduler.remote.utils.Host;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
|
||||
/**
|
||||
* task callback service
|
||||
*/
|
||||
@Service
|
||||
public class StateEventCallbackService {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(StateEventCallbackService.class);
|
||||
private static final int[] RETRY_BACKOFF = {1, 2, 3, 5, 10, 20, 40, 100, 100, 100, 100, 200, 200, 200};
|
||||
|
||||
/**
|
||||
* remote channels
|
||||
*/
|
||||
private static final ConcurrentHashMap<String, NettyRemoteChannel> REMOTE_CHANNELS = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* netty remoting client
|
||||
*/
|
||||
private final NettyRemotingClient nettyRemotingClient;
|
||||
|
||||
public StateEventCallbackService() {
|
||||
final NettyClientConfig clientConfig = new NettyClientConfig();
|
||||
this.nettyRemotingClient = new NettyRemotingClient(clientConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* add callback channel
|
||||
*
|
||||
* @param channel channel
|
||||
*/
|
||||
public void addRemoteChannel(String host, NettyRemoteChannel channel) {
|
||||
REMOTE_CHANNELS.put(host, channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* get callback channel
|
||||
*
|
||||
* @param host
|
||||
* @return callback channel
|
||||
*/
|
||||
private NettyRemoteChannel newRemoteChannel(Host host) {
|
||||
Channel newChannel;
|
||||
NettyRemoteChannel nettyRemoteChannel = REMOTE_CHANNELS.get(host.getAddress());
|
||||
if (nettyRemoteChannel != null) {
|
||||
if (nettyRemoteChannel.isActive()) {
|
||||
return nettyRemoteChannel;
|
||||
}
|
||||
}
|
||||
newChannel = nettyRemotingClient.getChannel(host);
|
||||
if (newChannel != null) {
|
||||
return newRemoteChannel(newChannel, host.getAddress());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int pause(int ntries) {
|
||||
return SLEEP_TIME_MILLIS * RETRY_BACKOFF[ntries % RETRY_BACKOFF.length];
|
||||
}
|
||||
|
||||
private NettyRemoteChannel newRemoteChannel(Channel newChannel, long opaque, String host) {
|
||||
NettyRemoteChannel remoteChannel = new NettyRemoteChannel(newChannel, opaque);
|
||||
addRemoteChannel(host, remoteChannel);
|
||||
return remoteChannel;
|
||||
}
|
||||
|
||||
private NettyRemoteChannel newRemoteChannel(Channel newChannel, String host) {
|
||||
NettyRemoteChannel remoteChannel = new NettyRemoteChannel(newChannel);
|
||||
addRemoteChannel(host, remoteChannel);
|
||||
return remoteChannel;
|
||||
}
|
||||
|
||||
/**
|
||||
* remove callback channels
|
||||
*/
|
||||
public void remove(String host) {
|
||||
REMOTE_CHANNELS.remove(host);
|
||||
}
|
||||
|
||||
/**
|
||||
* send result
|
||||
*
|
||||
* @param command command
|
||||
*/
|
||||
public void sendResult(String address, int port, Command command) {
|
||||
logger.info("send result, host:{}, command:{}", address, command.toString());
|
||||
Host host = new Host(address, port);
|
||||
NettyRemoteChannel nettyRemoteChannel = newRemoteChannel(host);
|
||||
if (nettyRemoteChannel != null) {
|
||||
nettyRemoteChannel.writeAndFlush(command);
|
||||
}
|
||||
}
|
||||
}
|
@ -55,7 +55,16 @@
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>jsr305</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-module-junit4</artifactId>
|
||||
|
@ -19,6 +19,7 @@ package org.apache.dolphinscheduler.server.entity;
|
||||
|
||||
import org.apache.dolphinscheduler.common.enums.ExecutionStatus;
|
||||
import org.apache.dolphinscheduler.common.enums.TaskTimeoutStrategy;
|
||||
import org.apache.dolphinscheduler.common.process.Property;
|
||||
import org.apache.dolphinscheduler.common.utils.JSONUtils;
|
||||
import org.apache.dolphinscheduler.remote.command.Command;
|
||||
import org.apache.dolphinscheduler.remote.command.TaskExecuteRequestCommand;
|
||||
@ -221,6 +222,19 @@ public class TaskExecutionContext implements Serializable {
|
||||
*/
|
||||
private String varPool;
|
||||
|
||||
/**
|
||||
* business param
|
||||
*/
|
||||
private Map<String, Property> paramsMap;
|
||||
|
||||
public Map<String, Property> getParamsMap() {
|
||||
return paramsMap;
|
||||
}
|
||||
|
||||
public void setParamsMap(Map<String, Property> paramsMap) {
|
||||
this.paramsMap = paramsMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* procedure TaskExecutionContext
|
||||
*/
|
||||
|
@ -24,14 +24,19 @@ import org.apache.dolphinscheduler.remote.NettyRemotingServer;
|
||||
import org.apache.dolphinscheduler.remote.command.CommandType;
|
||||
import org.apache.dolphinscheduler.remote.config.NettyServerConfig;
|
||||
import org.apache.dolphinscheduler.server.master.config.MasterConfig;
|
||||
import org.apache.dolphinscheduler.server.master.processor.StateEventProcessor;
|
||||
import org.apache.dolphinscheduler.server.master.processor.TaskAckProcessor;
|
||||
import org.apache.dolphinscheduler.server.master.processor.TaskKillResponseProcessor;
|
||||
import org.apache.dolphinscheduler.server.master.processor.TaskResponseProcessor;
|
||||
import org.apache.dolphinscheduler.server.master.registry.MasterRegistryClient;
|
||||
import org.apache.dolphinscheduler.server.master.runner.EventExecuteService;
|
||||
import org.apache.dolphinscheduler.server.master.runner.WorkflowExecuteThread;
|
||||
import org.apache.dolphinscheduler.server.master.runner.MasterSchedulerService;
|
||||
import org.apache.dolphinscheduler.service.bean.SpringApplicationContext;
|
||||
import org.apache.dolphinscheduler.service.quartz.QuartzExecutors;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.quartz.SchedulerException;
|
||||
@ -92,6 +97,11 @@ public class MasterServer implements IStoppable {
|
||||
@Autowired
|
||||
private MasterSchedulerService masterSchedulerService;
|
||||
|
||||
@Autowired
|
||||
private EventExecuteService eventExecuteService;
|
||||
|
||||
private ConcurrentHashMap<Integer, WorkflowExecuteThread> processInstanceExecMaps = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* master server startup, not use web service
|
||||
*
|
||||
@ -111,16 +121,28 @@ public class MasterServer implements IStoppable {
|
||||
NettyServerConfig serverConfig = new NettyServerConfig();
|
||||
serverConfig.setListenPort(masterConfig.getListenPort());
|
||||
this.nettyRemotingServer = new NettyRemotingServer(serverConfig);
|
||||
this.nettyRemotingServer.registerProcessor(CommandType.TASK_EXECUTE_RESPONSE, new TaskResponseProcessor());
|
||||
this.nettyRemotingServer.registerProcessor(CommandType.TASK_EXECUTE_ACK, new TaskAckProcessor());
|
||||
TaskAckProcessor ackProcessor = new TaskAckProcessor();
|
||||
ackProcessor.init(processInstanceExecMaps);
|
||||
TaskResponseProcessor taskResponseProcessor = new TaskResponseProcessor();
|
||||
taskResponseProcessor.init(processInstanceExecMaps);
|
||||
StateEventProcessor stateEventProcessor = new StateEventProcessor();
|
||||
stateEventProcessor.init(processInstanceExecMaps);
|
||||
this.nettyRemotingServer.registerProcessor(CommandType.TASK_EXECUTE_RESPONSE, ackProcessor);
|
||||
this.nettyRemotingServer.registerProcessor(CommandType.TASK_EXECUTE_ACK, taskResponseProcessor);
|
||||
this.nettyRemotingServer.registerProcessor(CommandType.TASK_KILL_RESPONSE, new TaskKillResponseProcessor());
|
||||
this.nettyRemotingServer.registerProcessor(CommandType.STATE_EVENT_REQUEST, stateEventProcessor);
|
||||
this.nettyRemotingServer.start();
|
||||
|
||||
// self tolerant
|
||||
this.masterRegistryClient.init(this.processInstanceExecMaps);
|
||||
this.masterRegistryClient.start();
|
||||
this.masterRegistryClient.setRegistryStoppable(this);
|
||||
|
||||
this.eventExecuteService.init(this.processInstanceExecMaps);
|
||||
this.eventExecuteService.start();
|
||||
// scheduler start
|
||||
this.masterSchedulerService.init(this.processInstanceExecMaps);
|
||||
|
||||
this.masterSchedulerService.start();
|
||||
|
||||
// start QuartzExecutors
|
||||
|
@ -45,6 +45,9 @@ public class MasterConfig {
|
||||
@Value("${master.heartbeat.interval:10}")
|
||||
private int masterHeartbeatInterval;
|
||||
|
||||
@Value("${master.state.wheel.interval:5}")
|
||||
private int stateWheelInterval;
|
||||
|
||||
@Value("${master.task.commit.retryTimes:5}")
|
||||
private int masterTaskCommitRetryTimes;
|
||||
|
||||
@ -139,4 +142,12 @@ public class MasterConfig {
|
||||
public void setMasterDispatchTaskNumber(int masterDispatchTaskNumber) {
|
||||
this.masterDispatchTaskNumber = masterDispatchTaskNumber;
|
||||
}
|
||||
|
||||
public int getStateWheelInterval() {
|
||||
return this.stateWheelInterval;
|
||||
}
|
||||
|
||||
public void setStateWheelInterval(int stateWheelInterval) {
|
||||
this.stateWheelInterval = stateWheelInterval;
|
||||
}
|
||||
}
|
@ -150,7 +150,7 @@ public class NettyExecutorManager extends AbstractExecutorManager<Boolean>{
|
||||
* @param command command
|
||||
* @throws ExecuteException if error throws ExecuteException
|
||||
*/
|
||||
private void doExecute(final Host host, final Command command) throws ExecuteException {
|
||||
public void doExecute(final Host host, final Command command) throws ExecuteException {
|
||||
/**
|
||||
* retry count,default retry 3
|
||||
*/
|
||||
|
@ -1,175 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dolphinscheduler.server.master.future;
|
||||
|
||||
|
||||
import org.apache.dolphinscheduler.remote.command.Command;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* task future
|
||||
*/
|
||||
public class TaskFuture {
|
||||
|
||||
private final static Logger LOGGER = LoggerFactory.getLogger(TaskFuture.class);
|
||||
|
||||
private final static ConcurrentHashMap<Long,TaskFuture> FUTURE_TABLE = new ConcurrentHashMap<>(256);
|
||||
|
||||
/**
|
||||
* request unique identification
|
||||
*/
|
||||
private final long opaque;
|
||||
|
||||
/**
|
||||
* timeout
|
||||
*/
|
||||
private final long timeoutMillis;
|
||||
|
||||
private final CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
private final long beginTimestamp = System.currentTimeMillis();
|
||||
|
||||
/**
|
||||
* response command
|
||||
*/
|
||||
private AtomicReference<Command> responseCommandReference = new AtomicReference<>();
|
||||
|
||||
private volatile boolean sendOk = true;
|
||||
|
||||
private AtomicReference<Throwable> causeReference;
|
||||
|
||||
public TaskFuture(long opaque, long timeoutMillis) {
|
||||
this.opaque = opaque;
|
||||
this.timeoutMillis = timeoutMillis;
|
||||
FUTURE_TABLE.put(opaque, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* wait for response
|
||||
* @return command
|
||||
* @throws InterruptedException if error throws InterruptedException
|
||||
*/
|
||||
public Command waitResponse() throws InterruptedException {
|
||||
this.latch.await(timeoutMillis, TimeUnit.MILLISECONDS);
|
||||
return this.responseCommandReference.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* put response
|
||||
*
|
||||
* @param responseCommand responseCommand
|
||||
*/
|
||||
public void putResponse(final Command responseCommand) {
|
||||
responseCommandReference.set(responseCommand);
|
||||
this.latch.countDown();
|
||||
FUTURE_TABLE.remove(opaque);
|
||||
}
|
||||
|
||||
/**
|
||||
* whether timeout
|
||||
* @return timeout
|
||||
*/
|
||||
public boolean isTimeout() {
|
||||
long diff = System.currentTimeMillis() - this.beginTimestamp;
|
||||
return diff > this.timeoutMillis;
|
||||
}
|
||||
|
||||
public static void notify(final Command responseCommand){
|
||||
TaskFuture taskFuture = FUTURE_TABLE.remove(responseCommand.getOpaque());
|
||||
if(taskFuture != null){
|
||||
taskFuture.putResponse(responseCommand);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean isSendOK() {
|
||||
return sendOk;
|
||||
}
|
||||
|
||||
public void setSendOk(boolean sendOk) {
|
||||
this.sendOk = sendOk;
|
||||
}
|
||||
|
||||
public void setCause(Throwable cause) {
|
||||
causeReference.set(cause);
|
||||
}
|
||||
|
||||
public Throwable getCause() {
|
||||
return causeReference.get();
|
||||
}
|
||||
|
||||
public long getOpaque() {
|
||||
return opaque;
|
||||
}
|
||||
|
||||
public long getTimeoutMillis() {
|
||||
return timeoutMillis;
|
||||
}
|
||||
|
||||
public long getBeginTimestamp() {
|
||||
return beginTimestamp;
|
||||
}
|
||||
|
||||
public Command getResponseCommand() {
|
||||
return responseCommandReference.get();
|
||||
}
|
||||
|
||||
public void setResponseCommand(Command responseCommand) {
|
||||
responseCommandReference.set(responseCommand);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* scan future table
|
||||
*/
|
||||
public static void scanFutureTable(){
|
||||
final List<TaskFuture> futureList = new LinkedList<>();
|
||||
Iterator<Map.Entry<Long, TaskFuture>> it = FUTURE_TABLE.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<Long, TaskFuture> next = it.next();
|
||||
TaskFuture future = next.getValue();
|
||||
if ((future.getBeginTimestamp() + future.getTimeoutMillis() + 1000) <= System.currentTimeMillis()) {
|
||||
futureList.add(future);
|
||||
it.remove();
|
||||
LOGGER.warn("remove timeout request : {}", future);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TaskFuture{" +
|
||||
"opaque=" + opaque +
|
||||
", timeoutMillis=" + timeoutMillis +
|
||||
", latch=" + latch +
|
||||
", beginTimestamp=" + beginTimestamp +
|
||||
", responseCommand=" + responseCommandReference.get() +
|
||||
", sendOk=" + sendOk +
|
||||
", cause=" + causeReference.get() +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.server.master.processor;
|
||||
|
||||
import org.apache.dolphinscheduler.common.utils.JSONUtils;
|
||||
import org.apache.dolphinscheduler.common.utils.Preconditions;
|
||||
import org.apache.dolphinscheduler.remote.command.Command;
|
||||
import org.apache.dolphinscheduler.remote.command.CommandType;
|
||||
import org.apache.dolphinscheduler.remote.processor.NettyRequestProcessor;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
|
||||
public class HostUpdateResponseProcessor implements NettyRequestProcessor {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(HostUpdateResponseProcessor.class);
|
||||
|
||||
@Override
|
||||
public void process(Channel channel, Command command) {
|
||||
Preconditions.checkArgument(CommandType.PROCESS_HOST_UPDATE_RESPONSE == command.getType(), String.format("invalid command type : %s", command.getType()));
|
||||
|
||||
HostUpdateResponseProcessor responseCommand = JSONUtils.parseObject(command.getBody(), HostUpdateResponseProcessor.class);
|
||||
logger.info("received process host response command : {}", responseCommand);
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.server.master.processor;
|
||||
|
||||
import org.apache.dolphinscheduler.common.enums.ExecutionStatus;
|
||||
import org.apache.dolphinscheduler.common.enums.StateEvent;
|
||||
import org.apache.dolphinscheduler.common.enums.StateEventType;
|
||||
import org.apache.dolphinscheduler.common.utils.JSONUtils;
|
||||
import org.apache.dolphinscheduler.common.utils.Preconditions;
|
||||
import org.apache.dolphinscheduler.remote.command.Command;
|
||||
import org.apache.dolphinscheduler.remote.command.CommandType;
|
||||
import org.apache.dolphinscheduler.remote.command.StateEventChangeCommand;
|
||||
import org.apache.dolphinscheduler.remote.processor.NettyRequestProcessor;
|
||||
import org.apache.dolphinscheduler.server.master.processor.queue.StateEventResponseService;
|
||||
import org.apache.dolphinscheduler.server.master.runner.WorkflowExecuteThread;
|
||||
import org.apache.dolphinscheduler.service.bean.SpringApplicationContext;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
|
||||
/**
|
||||
* handle state event received from master/api
|
||||
*/
|
||||
public class StateEventProcessor implements NettyRequestProcessor {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(StateEventProcessor.class);
|
||||
|
||||
private StateEventResponseService stateEventResponseService;
|
||||
|
||||
public StateEventProcessor() {
|
||||
stateEventResponseService = SpringApplicationContext.getBean(StateEventResponseService.class);
|
||||
}
|
||||
|
||||
public void init(ConcurrentHashMap<Integer, WorkflowExecuteThread> processInstanceExecMaps) {
|
||||
this.stateEventResponseService.init(processInstanceExecMaps);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(Channel channel, Command command) {
|
||||
Preconditions.checkArgument(CommandType.STATE_EVENT_REQUEST == command.getType(), String.format("invalid command type: %s", command.getType()));
|
||||
|
||||
StateEventChangeCommand stateEventChangeCommand = JSONUtils.parseObject(command.getBody(), StateEventChangeCommand.class);
|
||||
StateEvent stateEvent = new StateEvent();
|
||||
stateEvent.setExecutionStatus(ExecutionStatus.RUNNING_EXECUTION);
|
||||
stateEvent.setKey(stateEventChangeCommand.getKey());
|
||||
stateEvent.setProcessInstanceId(stateEventChangeCommand.getDestProcessInstanceId());
|
||||
stateEvent.setTaskInstanceId(stateEventChangeCommand.getDestTaskInstanceId());
|
||||
StateEventType type = stateEvent.getTaskInstanceId() == 0 ? StateEventType.PROCESS_STATE_CHANGE : StateEventType.TASK_STATE_CHANGE;
|
||||
stateEvent.setType(type);
|
||||
|
||||
logger.info("received command : {}", stateEvent.toString());
|
||||
stateEventResponseService.addResponse(stateEvent);
|
||||
}
|
||||
|
||||
}
|
@ -29,15 +29,18 @@ import org.apache.dolphinscheduler.server.master.cache.TaskInstanceCacheManager;
|
||||
import org.apache.dolphinscheduler.server.master.cache.impl.TaskInstanceCacheManagerImpl;
|
||||
import org.apache.dolphinscheduler.server.master.processor.queue.TaskResponseEvent;
|
||||
import org.apache.dolphinscheduler.server.master.processor.queue.TaskResponseService;
|
||||
import org.apache.dolphinscheduler.server.master.runner.WorkflowExecuteThread;
|
||||
import org.apache.dolphinscheduler.service.bean.SpringApplicationContext;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
|
||||
/**
|
||||
* task ack processor
|
||||
* task ack processor
|
||||
*/
|
||||
public class TaskAckProcessor implements NettyRequestProcessor {
|
||||
|
||||
@ -53,13 +56,18 @@ public class TaskAckProcessor implements NettyRequestProcessor {
|
||||
*/
|
||||
private final TaskInstanceCacheManager taskInstanceCacheManager;
|
||||
|
||||
public TaskAckProcessor(){
|
||||
public TaskAckProcessor() {
|
||||
this.taskResponseService = SpringApplicationContext.getBean(TaskResponseService.class);
|
||||
this.taskInstanceCacheManager = SpringApplicationContext.getBean(TaskInstanceCacheManagerImpl.class);
|
||||
}
|
||||
|
||||
public void init(ConcurrentHashMap<Integer, WorkflowExecuteThread> processInstanceExecMaps) {
|
||||
this.taskResponseService.init(processInstanceExecMaps);
|
||||
}
|
||||
|
||||
/**
|
||||
* task ack process
|
||||
*
|
||||
* @param channel channel channel
|
||||
* @param command command TaskExecuteAckCommand
|
||||
*/
|
||||
@ -82,7 +90,8 @@ public class TaskAckProcessor implements NettyRequestProcessor {
|
||||
taskAckCommand.getExecutePath(),
|
||||
taskAckCommand.getLogPath(),
|
||||
taskAckCommand.getTaskInstanceId(),
|
||||
channel);
|
||||
channel,
|
||||
taskAckCommand.getProcessInstanceId());
|
||||
|
||||
taskResponseService.addResponse(taskResponseEvent);
|
||||
}
|
||||
|
@ -28,15 +28,18 @@ import org.apache.dolphinscheduler.server.master.cache.TaskInstanceCacheManager;
|
||||
import org.apache.dolphinscheduler.server.master.cache.impl.TaskInstanceCacheManagerImpl;
|
||||
import org.apache.dolphinscheduler.server.master.processor.queue.TaskResponseEvent;
|
||||
import org.apache.dolphinscheduler.server.master.processor.queue.TaskResponseService;
|
||||
import org.apache.dolphinscheduler.server.master.runner.WorkflowExecuteThread;
|
||||
import org.apache.dolphinscheduler.service.bean.SpringApplicationContext;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
|
||||
/**
|
||||
* task response processor
|
||||
* task response processor
|
||||
*/
|
||||
public class TaskResponseProcessor implements NettyRequestProcessor {
|
||||
|
||||
@ -52,11 +55,15 @@ public class TaskResponseProcessor implements NettyRequestProcessor {
|
||||
*/
|
||||
private final TaskInstanceCacheManager taskInstanceCacheManager;
|
||||
|
||||
public TaskResponseProcessor(){
|
||||
public TaskResponseProcessor() {
|
||||
this.taskResponseService = SpringApplicationContext.getBean(TaskResponseService.class);
|
||||
this.taskInstanceCacheManager = SpringApplicationContext.getBean(TaskInstanceCacheManagerImpl.class);
|
||||
}
|
||||
|
||||
public void init(ConcurrentHashMap<Integer, WorkflowExecuteThread> processInstanceExecMaps) {
|
||||
this.taskResponseService.init(processInstanceExecMaps);
|
||||
}
|
||||
|
||||
/**
|
||||
* task final result response
|
||||
* need master process , state persistence
|
||||
@ -80,10 +87,9 @@ public class TaskResponseProcessor implements NettyRequestProcessor {
|
||||
responseCommand.getAppIds(),
|
||||
responseCommand.getTaskInstanceId(),
|
||||
responseCommand.getVarPool(),
|
||||
channel
|
||||
);
|
||||
channel,
|
||||
responseCommand.getProcessInstanceId()
|
||||
);
|
||||
taskResponseService.addResponse(taskResponseEvent);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.server.master.processor.queue;
|
||||
|
||||
import org.apache.dolphinscheduler.common.enums.ExecutionStatus;
|
||||
import org.apache.dolphinscheduler.common.enums.StateEvent;
|
||||
import org.apache.dolphinscheduler.common.thread.Stopper;
|
||||
import org.apache.dolphinscheduler.remote.command.StateEventResponseCommand;
|
||||
import org.apache.dolphinscheduler.server.master.runner.WorkflowExecuteThread;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
|
||||
/**
|
||||
* task manager
|
||||
*/
|
||||
@Component
|
||||
public class StateEventResponseService {
|
||||
|
||||
/**
|
||||
* logger
|
||||
*/
|
||||
private final Logger logger = LoggerFactory.getLogger(StateEventResponseService.class);
|
||||
|
||||
/**
|
||||
* attemptQueue
|
||||
*/
|
||||
private final BlockingQueue<StateEvent> eventQueue = new LinkedBlockingQueue<>(5000);
|
||||
|
||||
/**
|
||||
* task response worker
|
||||
*/
|
||||
private Thread responseWorker;
|
||||
|
||||
private ConcurrentHashMap<Integer, WorkflowExecuteThread> processInstanceMapper;
|
||||
|
||||
public void init(ConcurrentHashMap<Integer, WorkflowExecuteThread> processInstanceMapper) {
|
||||
if (this.processInstanceMapper == null) {
|
||||
this.processInstanceMapper = processInstanceMapper;
|
||||
}
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void start() {
|
||||
this.responseWorker = new StateEventResponseWorker();
|
||||
this.responseWorker.setName("StateEventResponseWorker");
|
||||
this.responseWorker.start();
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void stop() {
|
||||
this.responseWorker.interrupt();
|
||||
if (!eventQueue.isEmpty()) {
|
||||
List<StateEvent> remainEvents = new ArrayList<>(eventQueue.size());
|
||||
eventQueue.drainTo(remainEvents);
|
||||
for (StateEvent event : remainEvents) {
|
||||
this.persist(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* put task to attemptQueue
|
||||
*/
|
||||
public void addResponse(StateEvent stateEvent) {
|
||||
try {
|
||||
eventQueue.put(stateEvent);
|
||||
} catch (InterruptedException e) {
|
||||
logger.error("put state event : {} error :{}", stateEvent, e);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* task worker thread
|
||||
*/
|
||||
class StateEventResponseWorker extends Thread {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
while (Stopper.isRunning()) {
|
||||
try {
|
||||
// if not task , blocking here
|
||||
StateEvent stateEvent = eventQueue.take();
|
||||
persist(stateEvent);
|
||||
} catch (InterruptedException e) {
|
||||
logger.warn("persist task error", e);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
logger.info("StateEventResponseWorker stopped");
|
||||
}
|
||||
}
|
||||
|
||||
private void writeResponse(StateEvent stateEvent, ExecutionStatus status) {
|
||||
Channel channel = stateEvent.getChannel();
|
||||
if (channel != null) {
|
||||
StateEventResponseCommand command = new StateEventResponseCommand(status.getCode(), stateEvent.getKey());
|
||||
channel.writeAndFlush(command.convert2Command());
|
||||
}
|
||||
}
|
||||
|
||||
private void persist(StateEvent stateEvent) {
|
||||
try {
|
||||
if (!this.processInstanceMapper.containsKey(stateEvent.getProcessInstanceId())) {
|
||||
writeResponse(stateEvent, ExecutionStatus.FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
WorkflowExecuteThread workflowExecuteThread = this.processInstanceMapper.get(stateEvent.getProcessInstanceId());
|
||||
workflowExecuteThread.addStateEvent(stateEvent);
|
||||
writeResponse(stateEvent, ExecutionStatus.SUCCESS);
|
||||
} catch (Exception e) {
|
||||
logger.error("persist event queue error:", stateEvent.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public BlockingQueue<StateEvent> getEventQueue() {
|
||||
return eventQueue;
|
||||
}
|
||||
}
|
@ -92,6 +92,8 @@ public class TaskResponseEvent {
|
||||
* channel
|
||||
*/
|
||||
private Channel channel;
|
||||
|
||||
private int processInstanceId;
|
||||
|
||||
public static TaskResponseEvent newAck(ExecutionStatus state,
|
||||
Date startTime,
|
||||
@ -99,7 +101,8 @@ public class TaskResponseEvent {
|
||||
String executePath,
|
||||
String logPath,
|
||||
int taskInstanceId,
|
||||
Channel channel) {
|
||||
Channel channel,
|
||||
int processInstanceId) {
|
||||
TaskResponseEvent event = new TaskResponseEvent();
|
||||
event.setState(state);
|
||||
event.setStartTime(startTime);
|
||||
@ -109,6 +112,7 @@ public class TaskResponseEvent {
|
||||
event.setTaskInstanceId(taskInstanceId);
|
||||
event.setEvent(Event.ACK);
|
||||
event.setChannel(channel);
|
||||
event.setProcessInstanceId(processInstanceId);
|
||||
return event;
|
||||
}
|
||||
|
||||
@ -118,7 +122,8 @@ public class TaskResponseEvent {
|
||||
String appIds,
|
||||
int taskInstanceId,
|
||||
String varPool,
|
||||
Channel channel) {
|
||||
Channel channel,
|
||||
int processInstanceId) {
|
||||
TaskResponseEvent event = new TaskResponseEvent();
|
||||
event.setState(state);
|
||||
event.setEndTime(endTime);
|
||||
@ -128,6 +133,7 @@ public class TaskResponseEvent {
|
||||
event.setEvent(Event.RESULT);
|
||||
event.setVarPool(varPool);
|
||||
event.setChannel(channel);
|
||||
event.setProcessInstanceId(processInstanceId);
|
||||
return event;
|
||||
}
|
||||
|
||||
@ -227,4 +233,11 @@ public class TaskResponseEvent {
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
public int getProcessInstanceId() {
|
||||
return processInstanceId;
|
||||
}
|
||||
|
||||
public void setProcessInstanceId(int processInstanceId) {
|
||||
this.processInstanceId = processInstanceId;
|
||||
}
|
||||
}
|
||||
|
@ -19,15 +19,19 @@ package org.apache.dolphinscheduler.server.master.processor.queue;
|
||||
|
||||
import org.apache.dolphinscheduler.common.enums.Event;
|
||||
import org.apache.dolphinscheduler.common.enums.ExecutionStatus;
|
||||
import org.apache.dolphinscheduler.common.enums.StateEvent;
|
||||
import org.apache.dolphinscheduler.common.enums.StateEventType;
|
||||
import org.apache.dolphinscheduler.common.thread.Stopper;
|
||||
import org.apache.dolphinscheduler.dao.entity.TaskInstance;
|
||||
import org.apache.dolphinscheduler.remote.command.DBTaskAckCommand;
|
||||
import org.apache.dolphinscheduler.remote.command.DBTaskResponseCommand;
|
||||
import org.apache.dolphinscheduler.server.master.runner.WorkflowExecuteThread;
|
||||
import org.apache.dolphinscheduler.service.process.ProcessService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
@ -54,8 +58,7 @@ public class TaskResponseService {
|
||||
/**
|
||||
* attemptQueue
|
||||
*/
|
||||
private final BlockingQueue<TaskResponseEvent> eventQueue = new LinkedBlockingQueue<>(5000);
|
||||
|
||||
private final BlockingQueue<TaskResponseEvent> eventQueue = new LinkedBlockingQueue<>();
|
||||
|
||||
/**
|
||||
* process service
|
||||
@ -68,22 +71,34 @@ public class TaskResponseService {
|
||||
*/
|
||||
private Thread taskResponseWorker;
|
||||
|
||||
private ConcurrentHashMap<Integer, WorkflowExecuteThread> processInstanceMapper;
|
||||
|
||||
public void init(ConcurrentHashMap<Integer, WorkflowExecuteThread> processInstanceMapper) {
|
||||
if (this.processInstanceMapper == null) {
|
||||
this.processInstanceMapper = processInstanceMapper;
|
||||
}
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void start() {
|
||||
this.taskResponseWorker = new TaskResponseWorker();
|
||||
this.taskResponseWorker.setName("TaskResponseWorker");
|
||||
this.taskResponseWorker.setName("StateEventResponseWorker");
|
||||
this.taskResponseWorker.start();
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void stop() {
|
||||
this.taskResponseWorker.interrupt();
|
||||
if (!eventQueue.isEmpty()) {
|
||||
List<TaskResponseEvent> remainEvents = new ArrayList<>(eventQueue.size());
|
||||
eventQueue.drainTo(remainEvents);
|
||||
for (TaskResponseEvent event : remainEvents) {
|
||||
this.persist(event);
|
||||
try {
|
||||
this.taskResponseWorker.interrupt();
|
||||
if (!eventQueue.isEmpty()) {
|
||||
List<TaskResponseEvent> remainEvents = new ArrayList<>(eventQueue.size());
|
||||
eventQueue.drainTo(remainEvents);
|
||||
for (TaskResponseEvent event : remainEvents) {
|
||||
this.persist(event);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("stop error:", e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,7 +136,7 @@ public class TaskResponseService {
|
||||
logger.error("persist task error", e);
|
||||
}
|
||||
}
|
||||
logger.info("TaskResponseWorker stopped");
|
||||
logger.info("StateEventResponseWorker stopped");
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,18 +149,18 @@ public class TaskResponseService {
|
||||
Event event = taskResponseEvent.getEvent();
|
||||
Channel channel = taskResponseEvent.getChannel();
|
||||
|
||||
TaskInstance taskInstance = processService.findTaskInstanceById(taskResponseEvent.getTaskInstanceId());
|
||||
switch (event) {
|
||||
case ACK:
|
||||
try {
|
||||
TaskInstance taskInstance = processService.findTaskInstanceById(taskResponseEvent.getTaskInstanceId());
|
||||
if (taskInstance != null) {
|
||||
ExecutionStatus status = taskInstance.getState().typeIsFinished() ? taskInstance.getState() : taskResponseEvent.getState();
|
||||
processService.changeTaskState(taskInstance, status,
|
||||
taskResponseEvent.getStartTime(),
|
||||
taskResponseEvent.getWorkerAddress(),
|
||||
taskResponseEvent.getExecutePath(),
|
||||
taskResponseEvent.getLogPath(),
|
||||
taskResponseEvent.getTaskInstanceId());
|
||||
taskResponseEvent.getStartTime(),
|
||||
taskResponseEvent.getWorkerAddress(),
|
||||
taskResponseEvent.getExecutePath(),
|
||||
taskResponseEvent.getLogPath(),
|
||||
taskResponseEvent.getTaskInstanceId());
|
||||
}
|
||||
// if taskInstance is null (maybe deleted) . retry will be meaningless . so ack success
|
||||
DBTaskAckCommand taskAckCommand = new DBTaskAckCommand(ExecutionStatus.SUCCESS.getCode(), taskResponseEvent.getTaskInstanceId());
|
||||
@ -158,14 +173,13 @@ public class TaskResponseService {
|
||||
break;
|
||||
case RESULT:
|
||||
try {
|
||||
TaskInstance taskInstance = processService.findTaskInstanceById(taskResponseEvent.getTaskInstanceId());
|
||||
if (taskInstance != null) {
|
||||
processService.changeTaskState(taskInstance, taskResponseEvent.getState(),
|
||||
taskResponseEvent.getEndTime(),
|
||||
taskResponseEvent.getProcessId(),
|
||||
taskResponseEvent.getAppIds(),
|
||||
taskResponseEvent.getTaskInstanceId(),
|
||||
taskResponseEvent.getVarPool()
|
||||
taskResponseEvent.getEndTime(),
|
||||
taskResponseEvent.getProcessId(),
|
||||
taskResponseEvent.getAppIds(),
|
||||
taskResponseEvent.getTaskInstanceId(),
|
||||
taskResponseEvent.getVarPool()
|
||||
);
|
||||
}
|
||||
// if taskInstance is null (maybe deleted) . retry will be meaningless . so response success
|
||||
@ -180,6 +194,15 @@ public class TaskResponseService {
|
||||
default:
|
||||
throw new IllegalArgumentException("invalid event type : " + event);
|
||||
}
|
||||
WorkflowExecuteThread workflowExecuteThread = this.processInstanceMapper.get(taskResponseEvent.getProcessInstanceId());
|
||||
if (workflowExecuteThread != null) {
|
||||
StateEvent stateEvent = new StateEvent();
|
||||
stateEvent.setProcessInstanceId(taskResponseEvent.getProcessInstanceId());
|
||||
stateEvent.setTaskInstanceId(taskResponseEvent.getTaskInstanceId());
|
||||
stateEvent.setExecutionStatus(taskResponseEvent.getState());
|
||||
stateEvent.setType(StateEventType.TASK_STATE_CHANGE);
|
||||
workflowExecuteThread.addStateEvent(stateEvent);
|
||||
}
|
||||
}
|
||||
|
||||
public BlockingQueue<TaskResponseEvent> getEventQueue() {
|
||||
|
@ -25,6 +25,8 @@ import org.apache.dolphinscheduler.common.Constants;
|
||||
import org.apache.dolphinscheduler.common.IStoppable;
|
||||
import org.apache.dolphinscheduler.common.enums.ExecutionStatus;
|
||||
import org.apache.dolphinscheduler.common.enums.NodeType;
|
||||
import org.apache.dolphinscheduler.common.enums.StateEvent;
|
||||
import org.apache.dolphinscheduler.common.enums.StateEventType;
|
||||
import org.apache.dolphinscheduler.common.model.Server;
|
||||
import org.apache.dolphinscheduler.common.thread.ThreadUtils;
|
||||
import org.apache.dolphinscheduler.common.utils.DateUtils;
|
||||
@ -36,6 +38,7 @@ import org.apache.dolphinscheduler.remote.utils.NamedThreadFactory;
|
||||
import org.apache.dolphinscheduler.server.builder.TaskExecutionContextBuilder;
|
||||
import org.apache.dolphinscheduler.server.entity.TaskExecutionContext;
|
||||
import org.apache.dolphinscheduler.server.master.config.MasterConfig;
|
||||
import org.apache.dolphinscheduler.server.master.runner.WorkflowExecuteThread;
|
||||
import org.apache.dolphinscheduler.server.registry.HeartBeatTask;
|
||||
import org.apache.dolphinscheduler.server.utils.ProcessUtils;
|
||||
import org.apache.dolphinscheduler.service.process.ProcessService;
|
||||
@ -45,12 +48,11 @@ import org.apache.dolphinscheduler.spi.register.RegistryConnectState;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -90,6 +92,8 @@ public class MasterRegistryClient {
|
||||
*/
|
||||
private ScheduledExecutorService heartBeatExecutor;
|
||||
|
||||
private ConcurrentHashMap<Integer, WorkflowExecuteThread> processInstanceExecMaps;
|
||||
|
||||
/**
|
||||
* master start time
|
||||
*/
|
||||
@ -97,6 +101,13 @@ public class MasterRegistryClient {
|
||||
|
||||
private String localNodePath;
|
||||
|
||||
public void init(ConcurrentHashMap<Integer, WorkflowExecuteThread> processInstanceExecMaps) {
|
||||
this.startTime = DateUtils.dateToString(new Date());
|
||||
this.registryClient = RegistryClient.getInstance();
|
||||
this.heartBeatExecutor = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("HeartBeatExecutor"));
|
||||
this.processInstanceExecMaps = processInstanceExecMaps;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
String nodeLock = registryClient.getMasterStartUpLockPath();
|
||||
try {
|
||||
@ -182,7 +193,7 @@ public class MasterRegistryClient {
|
||||
failoverMaster(serverHost);
|
||||
break;
|
||||
case WORKER:
|
||||
failoverWorker(serverHost, true);
|
||||
failoverWorker(serverHost, true, true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -265,7 +276,7 @@ public class MasterRegistryClient {
|
||||
* @param workerHost worker host
|
||||
* @param needCheckWorkerAlive need check worker alive
|
||||
*/
|
||||
private void failoverWorker(String workerHost, boolean needCheckWorkerAlive) {
|
||||
private void failoverWorker(String workerHost, boolean needCheckWorkerAlive, boolean checkOwner) {
|
||||
logger.info("start worker[{}] failover ...", workerHost);
|
||||
List<TaskInstance> needFailoverTaskInstanceList = processService.queryNeedFailoverTaskInstances(workerHost);
|
||||
for (TaskInstance taskInstance : needFailoverTaskInstanceList) {
|
||||
@ -276,19 +287,39 @@ public class MasterRegistryClient {
|
||||
}
|
||||
|
||||
ProcessInstance processInstance = processService.findProcessInstanceDetailById(taskInstance.getProcessInstanceId());
|
||||
if (processInstance != null) {
|
||||
if (workerHost == null
|
||||
|| !checkOwner
|
||||
|| processInstance.getHost().equalsIgnoreCase(workerHost)) {
|
||||
// only failover the task owned myself if worker down.
|
||||
// failover master need handle worker at the same time
|
||||
if (processInstance == null) {
|
||||
logger.error("failover error, the process {} of task {} do not exists.",
|
||||
taskInstance.getProcessInstanceId(), taskInstance.getId());
|
||||
continue;
|
||||
}
|
||||
taskInstance.setProcessInstance(processInstance);
|
||||
|
||||
TaskExecutionContext taskExecutionContext = TaskExecutionContextBuilder.get()
|
||||
.buildTaskInstanceRelatedInfo(taskInstance)
|
||||
.buildProcessInstanceRelatedInfo(processInstance)
|
||||
.create();
|
||||
// only kill yarn job if exists , the local thread has exited
|
||||
ProcessUtils.killYarnJob(taskExecutionContext);
|
||||
|
||||
taskInstance.setState(ExecutionStatus.NEED_FAULT_TOLERANCE);
|
||||
processService.saveTaskInstance(taskInstance);
|
||||
if (!processInstanceExecMaps.containsKey(processInstance.getId())) {
|
||||
return;
|
||||
}
|
||||
WorkflowExecuteThread workflowExecuteThreadNotify = processInstanceExecMaps.get(processInstance.getId());
|
||||
StateEvent stateEvent = new StateEvent();
|
||||
stateEvent.setTaskInstanceId(taskInstance.getId());
|
||||
stateEvent.setType(StateEventType.TASK_STATE_CHANGE);
|
||||
stateEvent.setProcessInstanceId(processInstance.getId());
|
||||
stateEvent.setExecutionStatus(taskInstance.getState());
|
||||
workflowExecuteThreadNotify.addStateEvent(stateEvent);
|
||||
}
|
||||
|
||||
TaskExecutionContext taskExecutionContext = TaskExecutionContextBuilder.get()
|
||||
.buildTaskInstanceRelatedInfo(taskInstance)
|
||||
.buildProcessInstanceRelatedInfo(processInstance)
|
||||
.create();
|
||||
// only kill yarn job if exists , the local thread has exited
|
||||
ProcessUtils.killYarnJob(taskExecutionContext);
|
||||
|
||||
taskInstance.setState(ExecutionStatus.NEED_FAULT_TOLERANCE);
|
||||
processService.saveTaskInstance(taskInstance);
|
||||
}
|
||||
logger.info("end worker[{}] failover ...", workerHost);
|
||||
}
|
||||
@ -312,6 +343,7 @@ public class MasterRegistryClient {
|
||||
}
|
||||
processService.processNeedFailoverProcessInstances(processInstance);
|
||||
}
|
||||
failoverWorker(masterHost, true, false);
|
||||
|
||||
logger.info("master failover end");
|
||||
}
|
||||
@ -324,12 +356,6 @@ public class MasterRegistryClient {
|
||||
registryClient.releaseLock(registryClient.getMasterLockPath());
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
this.startTime = DateUtils.dateToString(new Date());
|
||||
this.registryClient = RegistryClient.getInstance();
|
||||
this.heartBeatExecutor = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("HeartBeatExecutor"));
|
||||
}
|
||||
|
||||
/**
|
||||
* registry
|
||||
@ -337,8 +363,6 @@ public class MasterRegistryClient {
|
||||
public void registry() {
|
||||
String address = NetUtils.getAddr(masterConfig.getListenPort());
|
||||
localNodePath = getMasterPath();
|
||||
registryClient.persistEphemeral(localNodePath, "");
|
||||
registryClient.addConnectionStateListener(new MasterRegistryConnectStateListener());
|
||||
int masterHeartbeatInterval = masterConfig.getMasterHeartbeatInterval();
|
||||
HeartBeatTask heartBeatTask = new HeartBeatTask(startTime,
|
||||
masterConfig.getMasterMaxCpuloadAvg(),
|
||||
@ -347,6 +371,8 @@ public class MasterRegistryClient {
|
||||
Constants.MASTER_TYPE,
|
||||
registryClient);
|
||||
|
||||
registryClient.persistEphemeral(localNodePath, heartBeatTask.heartBeatInfo());
|
||||
registryClient.addConnectionStateListener(new MasterRegistryConnectStateListener());
|
||||
this.heartBeatExecutor.scheduleAtFixedRate(heartBeatTask, masterHeartbeatInterval, masterHeartbeatInterval, TimeUnit.SECONDS);
|
||||
logger.info("master node : {} registry to ZK successfully with heartBeatInterval : {}s", address, masterHeartbeatInterval);
|
||||
|
||||
@ -369,13 +395,17 @@ public class MasterRegistryClient {
|
||||
* remove registry info
|
||||
*/
|
||||
public void unRegistry() {
|
||||
String address = getLocalAddress();
|
||||
String localNodePath = getMasterPath();
|
||||
registryClient.remove(localNodePath);
|
||||
logger.info("master node : {} unRegistry to register center.", address);
|
||||
heartBeatExecutor.shutdown();
|
||||
logger.info("heartbeat executor shutdown");
|
||||
registryClient.close();
|
||||
try {
|
||||
String address = getLocalAddress();
|
||||
String localNodePath = getMasterPath();
|
||||
registryClient.remove(localNodePath);
|
||||
logger.info("master node : {} unRegistry to register center.", address);
|
||||
heartBeatExecutor.shutdown();
|
||||
logger.info("heartbeat executor shutdown");
|
||||
registryClient.close();
|
||||
} catch (Exception e) {
|
||||
logger.error("remove registry path exception ", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -22,17 +22,21 @@ import static org.apache.dolphinscheduler.common.Constants.REGISTRY_DOLPHINSCHED
|
||||
|
||||
import org.apache.dolphinscheduler.common.Constants;
|
||||
import org.apache.dolphinscheduler.common.enums.NodeType;
|
||||
import org.apache.dolphinscheduler.common.model.Server;
|
||||
import org.apache.dolphinscheduler.common.utils.NetUtils;
|
||||
import org.apache.dolphinscheduler.common.utils.StringUtils;
|
||||
import org.apache.dolphinscheduler.dao.AlertDao;
|
||||
import org.apache.dolphinscheduler.dao.entity.WorkerGroup;
|
||||
import org.apache.dolphinscheduler.dao.mapper.WorkerGroupMapper;
|
||||
import org.apache.dolphinscheduler.remote.utils.NamedThreadFactory;
|
||||
import org.apache.dolphinscheduler.service.queue.MasterPriorityQueue;
|
||||
import org.apache.dolphinscheduler.service.registry.RegistryClient;
|
||||
import org.apache.dolphinscheduler.spi.register.DataChangeEvent;
|
||||
import org.apache.dolphinscheduler.spi.register.SubscribeListener;
|
||||
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@ -108,12 +112,26 @@ public class ServerNodeManager implements InitializingBean {
|
||||
@Autowired
|
||||
private WorkerGroupMapper workerGroupMapper;
|
||||
|
||||
private MasterPriorityQueue masterPriorityQueue = new MasterPriorityQueue();
|
||||
|
||||
/**
|
||||
* alert dao
|
||||
*/
|
||||
@Autowired
|
||||
private AlertDao alertDao;
|
||||
|
||||
public static volatile List<Integer> SLOT_LIST = new ArrayList<>();
|
||||
|
||||
public static volatile Integer MASTER_SIZE = 0;
|
||||
|
||||
public static Integer getSlot() {
|
||||
if (SLOT_LIST.size() > 0) {
|
||||
return SLOT_LIST.get(0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* init listener
|
||||
*
|
||||
@ -143,12 +161,11 @@ public class ServerNodeManager implements InitializingBean {
|
||||
/**
|
||||
* load nodes from zookeeper
|
||||
*/
|
||||
private void load() {
|
||||
public void load() {
|
||||
/**
|
||||
* master nodes from zookeeper
|
||||
*/
|
||||
Set<String> initMasterNodes = registryClient.getMasterNodesDirectly();
|
||||
syncMasterNodes(initMasterNodes);
|
||||
updateMasterNodes();
|
||||
|
||||
/**
|
||||
* worker group nodes from zookeeper
|
||||
@ -241,13 +258,11 @@ public class ServerNodeManager implements InitializingBean {
|
||||
try {
|
||||
if (dataChangeEvent.equals(DataChangeEvent.ADD)) {
|
||||
logger.info("master node : {} added.", path);
|
||||
Set<String> currentNodes = registryClient.getMasterNodesDirectly();
|
||||
syncMasterNodes(currentNodes);
|
||||
updateMasterNodes();
|
||||
}
|
||||
if (dataChangeEvent.equals(DataChangeEvent.REMOVE)) {
|
||||
logger.info("master node : {} down.", path);
|
||||
Set<String> currentNodes = registryClient.getMasterNodesDirectly();
|
||||
syncMasterNodes(currentNodes);
|
||||
updateMasterNodes();
|
||||
alertDao.sendServerStopedAlert(1, path, "MASTER");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
@ -257,6 +272,23 @@ public class ServerNodeManager implements InitializingBean {
|
||||
}
|
||||
}
|
||||
|
||||
private void updateMasterNodes() {
|
||||
SLOT_LIST.clear();
|
||||
this.masterNodes.clear();
|
||||
String nodeLock = registryClient.getMasterLockPath();
|
||||
try {
|
||||
registryClient.getLock(nodeLock);
|
||||
Set<String> currentNodes = registryClient.getMasterNodesDirectly();
|
||||
List<Server> masterNodes = registryClient.getServerList(NodeType.MASTER);
|
||||
syncMasterNodes(currentNodes, masterNodes);
|
||||
} catch (Exception e) {
|
||||
logger.error("update master nodes error", e);
|
||||
} finally {
|
||||
registryClient.releaseLock(nodeLock);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* get master nodes
|
||||
*
|
||||
@ -274,13 +306,23 @@ public class ServerNodeManager implements InitializingBean {
|
||||
/**
|
||||
* sync master nodes
|
||||
*
|
||||
* @param nodes master nodes
|
||||
* @param nodes master nodes
|
||||
* @param masterNodes
|
||||
*/
|
||||
private void syncMasterNodes(Set<String> nodes) {
|
||||
private void syncMasterNodes(Set<String> nodes, List<Server> masterNodes) {
|
||||
masterLock.lock();
|
||||
try {
|
||||
masterNodes.clear();
|
||||
masterNodes.addAll(nodes);
|
||||
this.masterNodes.addAll(nodes);
|
||||
this.masterPriorityQueue.clear();
|
||||
this.masterPriorityQueue.putList(masterNodes);
|
||||
int index = masterPriorityQueue.getIndex(NetUtils.getHost());
|
||||
if (index >= 0) {
|
||||
MASTER_SIZE = nodes.size();
|
||||
SLOT_LIST.add(masterPriorityQueue.getIndex(NetUtils.getHost()));
|
||||
}
|
||||
logger.info("update master nodes, master size: {}, slot: {}",
|
||||
MASTER_SIZE, SLOT_LIST.toString()
|
||||
);
|
||||
} finally {
|
||||
masterLock.unlock();
|
||||
}
|
||||
@ -290,7 +332,7 @@ public class ServerNodeManager implements InitializingBean {
|
||||
* sync worker group nodes
|
||||
*
|
||||
* @param workerGroup worker group
|
||||
* @param nodes worker nodes
|
||||
* @param nodes worker nodes
|
||||
*/
|
||||
private void syncWorkerGroupNodes(String workerGroup, Set<String> nodes) {
|
||||
workerGroupLock.lock();
|
||||
|
@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.server.master.runner;
|
||||
|
||||
import org.apache.dolphinscheduler.common.enums.ExecutionStatus;
|
||||
import org.apache.dolphinscheduler.common.enums.StateEvent;
|
||||
import org.apache.dolphinscheduler.common.enums.StateEventType;
|
||||
import org.apache.dolphinscheduler.common.thread.Stopper;
|
||||
import org.apache.dolphinscheduler.common.thread.ThreadUtils;
|
||||
import org.apache.dolphinscheduler.common.utils.NetUtils;
|
||||
import org.apache.dolphinscheduler.common.utils.StringUtils;
|
||||
import org.apache.dolphinscheduler.dao.entity.ProcessInstance;
|
||||
import org.apache.dolphinscheduler.dao.entity.TaskInstance;
|
||||
import org.apache.dolphinscheduler.remote.command.StateEventChangeCommand;
|
||||
import org.apache.dolphinscheduler.remote.processor.StateEventCallbackService;
|
||||
import org.apache.dolphinscheduler.server.master.config.MasterConfig;
|
||||
import org.apache.dolphinscheduler.service.bean.SpringApplicationContext;
|
||||
import org.apache.dolphinscheduler.service.process.ProcessService;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
|
||||
@Service
|
||||
public class EventExecuteService extends Thread {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(EventExecuteService.class);
|
||||
|
||||
|
||||
/**
|
||||
* dolphinscheduler database interface
|
||||
*/
|
||||
@Autowired
|
||||
private ProcessService processService;
|
||||
|
||||
@Autowired
|
||||
private MasterConfig masterConfig;
|
||||
|
||||
private ExecutorService eventExecService;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private StateEventCallbackService stateEventCallbackService;
|
||||
|
||||
|
||||
private ConcurrentHashMap<Integer, WorkflowExecuteThread> processInstanceExecMaps;
|
||||
private ConcurrentHashMap<String, WorkflowExecuteThread> eventHandlerMap = new ConcurrentHashMap();
|
||||
ListeningExecutorService listeningExecutorService;
|
||||
|
||||
public void init(ConcurrentHashMap<Integer, WorkflowExecuteThread> processInstanceExecMaps) {
|
||||
|
||||
eventExecService = ThreadUtils.newDaemonFixedThreadExecutor("MasterEventExecution", masterConfig.getMasterExecThreads());
|
||||
|
||||
this.processInstanceExecMaps = processInstanceExecMaps;
|
||||
|
||||
listeningExecutorService = MoreExecutors.listeningDecorator(eventExecService);
|
||||
this.stateEventCallbackService = SpringApplicationContext.getBean(StateEventCallbackService.class);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void start() {
|
||||
super.setName("EventServiceStarted");
|
||||
super.start();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
eventExecService.shutdown();
|
||||
logger.info("event service stopped...");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
logger.info("Event service started");
|
||||
while (Stopper.isRunning()) {
|
||||
try {
|
||||
eventHandler();
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Event service thread error", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void eventHandler() {
|
||||
for (WorkflowExecuteThread workflowExecuteThread : this.processInstanceExecMaps.values()) {
|
||||
if (workflowExecuteThread.eventSize() == 0
|
||||
|| StringUtils.isEmpty(workflowExecuteThread.getKey())
|
||||
|| eventHandlerMap.containsKey(workflowExecuteThread.getKey())) {
|
||||
continue;
|
||||
}
|
||||
int processInstanceId = workflowExecuteThread.getProcessInstance().getId();
|
||||
logger.info("handle process instance : {} events, count:{}",
|
||||
processInstanceId,
|
||||
workflowExecuteThread.eventSize());
|
||||
logger.info("already exists handler process size:{}", this.eventHandlerMap.size());
|
||||
eventHandlerMap.put(workflowExecuteThread.getKey(), workflowExecuteThread);
|
||||
ListenableFuture future = this.listeningExecutorService.submit(workflowExecuteThread);
|
||||
FutureCallback futureCallback = new FutureCallback() {
|
||||
@Override
|
||||
public void onSuccess(Object o) {
|
||||
if (workflowExecuteThread.workFlowFinish()) {
|
||||
processInstanceExecMaps.remove(processInstanceId);
|
||||
notifyProcessChanged();
|
||||
logger.info("process instance {} finished.", processInstanceId);
|
||||
}
|
||||
if (workflowExecuteThread.getProcessInstance().getId() != processInstanceId) {
|
||||
processInstanceExecMaps.remove(processInstanceId);
|
||||
processInstanceExecMaps.put(workflowExecuteThread.getProcessInstance().getId(), workflowExecuteThread);
|
||||
|
||||
}
|
||||
eventHandlerMap.remove(workflowExecuteThread.getKey());
|
||||
}
|
||||
|
||||
private void notifyProcessChanged() {
|
||||
Map<ProcessInstance, TaskInstance> fatherMaps
|
||||
= processService.notifyProcessList(processInstanceId, 0);
|
||||
|
||||
for (ProcessInstance processInstance : fatherMaps.keySet()) {
|
||||
String address = NetUtils.getAddr(masterConfig.getListenPort());
|
||||
if (processInstance.getHost().equalsIgnoreCase(address)) {
|
||||
notifyMyself(processInstance, fatherMaps.get(processInstance));
|
||||
} else {
|
||||
notifyProcess(processInstance, fatherMaps.get(processInstance));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyMyself(ProcessInstance processInstance, TaskInstance taskInstance) {
|
||||
logger.info("notify process {} task {} state change", processInstance.getId(), taskInstance.getId());
|
||||
if (!processInstanceExecMaps.containsKey(processInstance.getId())) {
|
||||
return;
|
||||
}
|
||||
WorkflowExecuteThread workflowExecuteThreadNotify = processInstanceExecMaps.get(processInstance.getId());
|
||||
StateEvent stateEvent = new StateEvent();
|
||||
stateEvent.setTaskInstanceId(taskInstance.getId());
|
||||
stateEvent.setType(StateEventType.TASK_STATE_CHANGE);
|
||||
stateEvent.setProcessInstanceId(processInstance.getId());
|
||||
stateEvent.setExecutionStatus(ExecutionStatus.RUNNING_EXECUTION);
|
||||
workflowExecuteThreadNotify.addStateEvent(stateEvent);
|
||||
}
|
||||
|
||||
private void notifyProcess(ProcessInstance processInstance, TaskInstance taskInstance) {
|
||||
String host = processInstance.getHost();
|
||||
if (StringUtils.isEmpty(host)) {
|
||||
logger.info("process {} host is empty, cannot notify task {} now.",
|
||||
processInstance.getId(), taskInstance.getId());
|
||||
return;
|
||||
}
|
||||
String address = host.split(":")[0];
|
||||
int port = Integer.parseInt(host.split(":")[1]);
|
||||
logger.info("notify process {} task {} state change, host:{}",
|
||||
processInstance.getId(), taskInstance.getId(), host);
|
||||
StateEventChangeCommand stateEventChangeCommand = new StateEventChangeCommand(
|
||||
processInstanceId, 0, workflowExecuteThread.getProcessInstance().getState(), processInstance.getId(), taskInstance.getId()
|
||||
);
|
||||
|
||||
stateEventCallbackService.sendResult(address, port, stateEventChangeCommand.convert2Command());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable throwable) {
|
||||
}
|
||||
};
|
||||
Futures.addCallback(future, futureCallback, this.listeningExecutorService);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,324 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.server.master.runner;
|
||||
|
||||
import org.apache.dolphinscheduler.common.enums.ExecutionStatus;
|
||||
import org.apache.dolphinscheduler.common.enums.TaskTimeoutStrategy;
|
||||
import org.apache.dolphinscheduler.common.enums.TimeoutFlag;
|
||||
import org.apache.dolphinscheduler.common.task.TaskTimeoutParameter;
|
||||
import org.apache.dolphinscheduler.common.utils.JSONUtils;
|
||||
import org.apache.dolphinscheduler.dao.AlertDao;
|
||||
import org.apache.dolphinscheduler.dao.entity.ProcessInstance;
|
||||
import org.apache.dolphinscheduler.dao.entity.TaskDefinition;
|
||||
import org.apache.dolphinscheduler.dao.entity.TaskInstance;
|
||||
import org.apache.dolphinscheduler.server.master.config.MasterConfig;
|
||||
import org.apache.dolphinscheduler.service.bean.SpringApplicationContext;
|
||||
import org.apache.dolphinscheduler.service.process.ProcessService;
|
||||
import org.apache.dolphinscheduler.service.queue.TaskPriority;
|
||||
import org.apache.dolphinscheduler.service.queue.TaskPriorityQueue;
|
||||
import org.apache.dolphinscheduler.service.queue.TaskPriorityQueueImpl;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* master task exec base class
|
||||
*/
|
||||
public class MasterBaseTaskExecThread implements Callable<Boolean> {
|
||||
|
||||
/**
|
||||
* logger of MasterBaseTaskExecThread
|
||||
*/
|
||||
protected Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
|
||||
/**
|
||||
* process service
|
||||
*/
|
||||
protected ProcessService processService;
|
||||
|
||||
/**
|
||||
* alert database access
|
||||
*/
|
||||
protected AlertDao alertDao;
|
||||
|
||||
/**
|
||||
* process instance
|
||||
*/
|
||||
protected ProcessInstance processInstance;
|
||||
|
||||
/**
|
||||
* task instance
|
||||
*/
|
||||
protected TaskInstance taskInstance;
|
||||
|
||||
/**
|
||||
* whether need cancel
|
||||
*/
|
||||
protected boolean cancel;
|
||||
|
||||
/**
|
||||
* master config
|
||||
*/
|
||||
protected MasterConfig masterConfig;
|
||||
|
||||
/**
|
||||
* taskUpdateQueue
|
||||
*/
|
||||
private TaskPriorityQueue taskUpdateQueue;
|
||||
|
||||
/**
|
||||
* whether need check task time out.
|
||||
*/
|
||||
protected boolean checkTimeoutFlag = false;
|
||||
|
||||
/**
|
||||
* task timeout parameters
|
||||
*/
|
||||
protected TaskTimeoutParameter taskTimeoutParameter;
|
||||
|
||||
/**
|
||||
* constructor of MasterBaseTaskExecThread
|
||||
*
|
||||
* @param taskInstance task instance
|
||||
*/
|
||||
public MasterBaseTaskExecThread(TaskInstance taskInstance) {
|
||||
this.processService = SpringApplicationContext.getBean(ProcessService.class);
|
||||
this.alertDao = SpringApplicationContext.getBean(AlertDao.class);
|
||||
this.cancel = false;
|
||||
this.taskInstance = taskInstance;
|
||||
this.masterConfig = SpringApplicationContext.getBean(MasterConfig.class);
|
||||
this.taskUpdateQueue = SpringApplicationContext.getBean(TaskPriorityQueueImpl.class);
|
||||
initTaskParams();
|
||||
}
|
||||
|
||||
/**
|
||||
* init task ordinary parameters
|
||||
*/
|
||||
private void initTaskParams() {
|
||||
initTimeoutParams();
|
||||
}
|
||||
|
||||
/**
|
||||
* init task timeout parameters
|
||||
*/
|
||||
private void initTimeoutParams() {
|
||||
TaskDefinition taskDefinition = processService.findTaskDefinition(taskInstance.getTaskCode(), taskInstance.getTaskDefinitionVersion());
|
||||
boolean timeoutEnable = taskDefinition.getTimeoutFlag() == TimeoutFlag.OPEN;
|
||||
taskTimeoutParameter = new TaskTimeoutParameter(timeoutEnable,
|
||||
taskDefinition.getTimeoutNotifyStrategy(),
|
||||
taskDefinition.getTimeout());
|
||||
if (taskTimeoutParameter.getEnable()) {
|
||||
checkTimeoutFlag = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get task instance
|
||||
*
|
||||
* @return TaskInstance
|
||||
*/
|
||||
public TaskInstance getTaskInstance() {
|
||||
return this.taskInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* kill master base task exec thread
|
||||
*/
|
||||
public void kill() {
|
||||
this.cancel = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* submit master base task exec thread
|
||||
*
|
||||
* @return TaskInstance
|
||||
*/
|
||||
protected TaskInstance submit() {
|
||||
Integer commitRetryTimes = masterConfig.getMasterTaskCommitRetryTimes();
|
||||
Integer commitRetryInterval = masterConfig.getMasterTaskCommitInterval();
|
||||
|
||||
int retryTimes = 1;
|
||||
boolean submitDB = false;
|
||||
boolean submitTask = false;
|
||||
TaskInstance task = null;
|
||||
while (retryTimes <= commitRetryTimes) {
|
||||
try {
|
||||
if (!submitDB) {
|
||||
// submit task to db
|
||||
task = processService.submitTask(taskInstance);
|
||||
if (task != null && task.getId() != 0) {
|
||||
submitDB = true;
|
||||
}
|
||||
}
|
||||
if (submitDB && !submitTask) {
|
||||
// dispatch task
|
||||
submitTask = dispatchTask(task);
|
||||
}
|
||||
if (submitDB && submitTask) {
|
||||
return task;
|
||||
}
|
||||
if (!submitDB) {
|
||||
logger.error("task commit to db failed , taskId {} has already retry {} times, please check the database", taskInstance.getId(), retryTimes);
|
||||
} else if (!submitTask) {
|
||||
logger.error("task commit failed , taskId {} has already retry {} times, please check", taskInstance.getId(), retryTimes);
|
||||
}
|
||||
Thread.sleep(commitRetryInterval);
|
||||
} catch (Exception e) {
|
||||
logger.error("task commit to mysql and dispatcht task failed", e);
|
||||
}
|
||||
retryTimes += 1;
|
||||
}
|
||||
return task;
|
||||
}
|
||||
|
||||
/**
|
||||
* dispatch task
|
||||
*
|
||||
* @param taskInstance taskInstance
|
||||
* @return whether submit task success
|
||||
*/
|
||||
public Boolean dispatchTask(TaskInstance taskInstance) {
|
||||
|
||||
try {
|
||||
if (taskInstance.isConditionsTask()
|
||||
|| taskInstance.isDependTask()
|
||||
|| taskInstance.isSubProcess()) {
|
||||
return true;
|
||||
}
|
||||
if (taskInstance.getState().typeIsFinished()) {
|
||||
logger.info(String.format("submit task , but task [%s] state [%s] is already finished. ", taskInstance.getName(), taskInstance.getState().toString()));
|
||||
return true;
|
||||
}
|
||||
// task cannot be submitted because its execution state is RUNNING or DELAY.
|
||||
if (taskInstance.getState() == ExecutionStatus.RUNNING_EXECUTION
|
||||
|| taskInstance.getState() == ExecutionStatus.DELAY_EXECUTION) {
|
||||
logger.info("submit task, but the status of the task {} is already running or delayed.", taskInstance.getName());
|
||||
return true;
|
||||
}
|
||||
logger.info("task ready to submit: {}", taskInstance);
|
||||
|
||||
/**
|
||||
* taskPriority
|
||||
*/
|
||||
TaskPriority taskPriority = buildTaskPriority(processInstance.getProcessInstancePriority().getCode(),
|
||||
processInstance.getId(),
|
||||
taskInstance.getProcessInstancePriority().getCode(),
|
||||
taskInstance.getId(),
|
||||
org.apache.dolphinscheduler.common.Constants.DEFAULT_WORKER_GROUP);
|
||||
taskUpdateQueue.put(taskPriority);
|
||||
logger.info(String.format("master submit success, task : %s", taskInstance.getName()));
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
logger.error("submit task Exception: ", e);
|
||||
logger.error("task error : %s", JSONUtils.toJsonString(taskInstance));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* buildTaskPriority
|
||||
*
|
||||
* @param processInstancePriority processInstancePriority
|
||||
* @param processInstanceId processInstanceId
|
||||
* @param taskInstancePriority taskInstancePriority
|
||||
* @param taskInstanceId taskInstanceId
|
||||
* @param workerGroup workerGroup
|
||||
* @return TaskPriority
|
||||
*/
|
||||
private TaskPriority buildTaskPriority(int processInstancePriority,
|
||||
int processInstanceId,
|
||||
int taskInstancePriority,
|
||||
int taskInstanceId,
|
||||
String workerGroup) {
|
||||
return new TaskPriority(processInstancePriority, processInstanceId,
|
||||
taskInstancePriority, taskInstanceId, workerGroup);
|
||||
}
|
||||
|
||||
/**
|
||||
* submit wait complete
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
protected Boolean submitWaitComplete() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* call
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
@Override
|
||||
public Boolean call() {
|
||||
this.processInstance = processService.findProcessInstanceById(taskInstance.getProcessInstanceId());
|
||||
return submitWaitComplete();
|
||||
}
|
||||
|
||||
/**
|
||||
* alert time out
|
||||
*/
|
||||
protected boolean alertTimeout() {
|
||||
if (TaskTimeoutStrategy.FAILED == this.taskTimeoutParameter.getStrategy()) {
|
||||
return true;
|
||||
}
|
||||
logger.warn("process id:{} process name:{} task id: {},name:{} execution time out",
|
||||
processInstance.getId(), processInstance.getName(), taskInstance.getId(), taskInstance.getName());
|
||||
// send warn mail
|
||||
alertDao.sendTaskTimeoutAlert(processInstance.getWarningGroupId(), processInstance.getId(), processInstance.getName(),
|
||||
taskInstance.getId(), taskInstance.getName());
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* handle time out for time out strategy warn&&failed
|
||||
*/
|
||||
protected void handleTimeoutFailed() {
|
||||
if (TaskTimeoutStrategy.WARN == this.taskTimeoutParameter.getStrategy()) {
|
||||
return;
|
||||
}
|
||||
logger.info("process id:{} name:{} task id:{} name:{} cancel because of timeout.",
|
||||
processInstance.getId(), processInstance.getName(), taskInstance.getId(), taskInstance.getName());
|
||||
this.cancel = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* check task remain time valid
|
||||
*/
|
||||
protected boolean checkTaskTimeout() {
|
||||
if (!checkTimeoutFlag || taskInstance.getStartTime() == null) {
|
||||
return false;
|
||||
}
|
||||
long remainTime = getRemainTime(taskTimeoutParameter.getInterval() * 60L);
|
||||
return remainTime <= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* get remain time
|
||||
*
|
||||
* @return remain time
|
||||
*/
|
||||
protected long getRemainTime(long timeoutSeconds) {
|
||||
Date startTime = taskInstance.getStartTime();
|
||||
long usedTime = (System.currentTimeMillis() - startTime.getTime()) / 1000;
|
||||
return timeoutSeconds - usedTime;
|
||||
}
|
||||
}
|
@ -24,25 +24,28 @@ import org.apache.dolphinscheduler.common.utils.NetUtils;
|
||||
import org.apache.dolphinscheduler.common.utils.OSUtils;
|
||||
import org.apache.dolphinscheduler.dao.entity.Command;
|
||||
import org.apache.dolphinscheduler.dao.entity.ProcessInstance;
|
||||
import org.apache.dolphinscheduler.dao.entity.TaskInstance;
|
||||
import org.apache.dolphinscheduler.remote.NettyRemotingClient;
|
||||
import org.apache.dolphinscheduler.remote.config.NettyClientConfig;
|
||||
import org.apache.dolphinscheduler.server.master.config.MasterConfig;
|
||||
import org.apache.dolphinscheduler.server.master.dispatch.executor.NettyExecutorManager;
|
||||
import org.apache.dolphinscheduler.server.master.registry.MasterRegistryClient;
|
||||
import org.apache.dolphinscheduler.server.master.registry.ServerNodeManager;
|
||||
import org.apache.dolphinscheduler.service.alert.ProcessAlertManager;
|
||||
import org.apache.dolphinscheduler.service.process.ProcessService;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* master scheduler thread
|
||||
* master scheduler thread
|
||||
*/
|
||||
@Service
|
||||
public class MasterSchedulerService extends Thread {
|
||||
@ -77,30 +80,46 @@ public class MasterSchedulerService extends Thread {
|
||||
private ProcessAlertManager processAlertManager;
|
||||
|
||||
/**
|
||||
* netty remoting client
|
||||
* netty remoting client
|
||||
*/
|
||||
private NettyRemotingClient nettyRemotingClient;
|
||||
|
||||
@Autowired
|
||||
NettyExecutorManager nettyExecutorManager;
|
||||
|
||||
/**
|
||||
* master exec service
|
||||
*/
|
||||
private ThreadPoolExecutor masterExecService;
|
||||
|
||||
|
||||
private ConcurrentHashMap<Integer, WorkflowExecuteThread> processInstanceExecMaps;
|
||||
ConcurrentHashMap<Integer, ProcessInstance> processTimeoutCheckList = new ConcurrentHashMap<>();
|
||||
ConcurrentHashMap<Integer, TaskInstance> taskTimeoutCheckList = new ConcurrentHashMap<>();
|
||||
|
||||
private StateWheelExecuteThread stateWheelExecuteThread;
|
||||
|
||||
/**
|
||||
* constructor of MasterSchedulerService
|
||||
*/
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
this.masterExecService = (ThreadPoolExecutor)ThreadUtils.newDaemonFixedThreadExecutor("Master-Exec-Thread", masterConfig.getMasterExecThreads());
|
||||
public void init(ConcurrentHashMap<Integer, WorkflowExecuteThread> processInstanceExecMaps) {
|
||||
this.processInstanceExecMaps = processInstanceExecMaps;
|
||||
this.masterExecService = (ThreadPoolExecutor) ThreadUtils.newDaemonFixedThreadExecutor("Master-Exec-Thread", masterConfig.getMasterExecThreads());
|
||||
NettyClientConfig clientConfig = new NettyClientConfig();
|
||||
this.nettyRemotingClient = new NettyRemotingClient(clientConfig);
|
||||
|
||||
stateWheelExecuteThread = new StateWheelExecuteThread(processTimeoutCheckList,
|
||||
taskTimeoutCheckList,
|
||||
this.processInstanceExecMaps,
|
||||
masterConfig.getStateWheelInterval() * Constants.SLEEP_TIME_MILLIS);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void start() {
|
||||
super.setName("MasterSchedulerService");
|
||||
super.start();
|
||||
this.stateWheelExecuteThread.start();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
@ -131,10 +150,6 @@ public class MasterSchedulerService extends Thread {
|
||||
Thread.sleep(Constants.SLEEP_TIME_MILLIS);
|
||||
continue;
|
||||
}
|
||||
// todo 串行执行 为何还需要判断状态?
|
||||
/* if (zkMasterClient.getZkClient().getState() == CuratorFrameworkState.STARTED) {
|
||||
scheduleProcess();
|
||||
}*/
|
||||
scheduleProcess();
|
||||
} catch (Exception e) {
|
||||
logger.error("master scheduler thread error", e);
|
||||
@ -142,45 +157,80 @@ public class MasterSchedulerService extends Thread {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. get command by slot
|
||||
* 2. donot handle command if slot is empty
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
private void scheduleProcess() throws Exception {
|
||||
|
||||
try {
|
||||
masterRegistryClient.blockAcquireMutex();
|
||||
int activeCount = masterExecService.getActiveCount();
|
||||
// make sure to scan and delete command table in one transaction
|
||||
Command command = findOneCommand();
|
||||
if (command != null) {
|
||||
logger.info("find one command: id: {}, type: {}", command.getId(), command.getCommandType());
|
||||
try {
|
||||
ProcessInstance processInstance = processService.handleCommand(logger,
|
||||
getLocalAddress(),
|
||||
this.masterConfig.getMasterExecThreads() - activeCount, command);
|
||||
if (processInstance != null) {
|
||||
WorkflowExecuteThread workflowExecuteThread = new WorkflowExecuteThread(
|
||||
processInstance
|
||||
, processService
|
||||
, nettyExecutorManager
|
||||
, processAlertManager
|
||||
, masterConfig
|
||||
, taskTimeoutCheckList);
|
||||
|
||||
int activeCount = masterExecService.getActiveCount();
|
||||
// make sure to scan and delete command table in one transaction
|
||||
Command command = processService.findOneCommand();
|
||||
if (command != null) {
|
||||
logger.info("find one command: id: {}, type: {}", command.getId(),command.getCommandType());
|
||||
|
||||
try {
|
||||
|
||||
ProcessInstance processInstance = processService.handleCommand(logger,
|
||||
getLocalAddress(),
|
||||
this.masterConfig.getMasterExecThreads() - activeCount, command);
|
||||
if (processInstance != null) {
|
||||
logger.info("start master exec thread , split DAG ...");
|
||||
masterExecService.execute(
|
||||
new MasterExecThread(
|
||||
processInstance
|
||||
, processService
|
||||
, nettyRemotingClient
|
||||
, processAlertManager
|
||||
, masterConfig));
|
||||
this.processInstanceExecMaps.put(processInstance.getId(), workflowExecuteThread);
|
||||
if (processInstance.getTimeout() > 0) {
|
||||
this.processTimeoutCheckList.put(processInstance.getId(), processInstance);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("scan command error ", e);
|
||||
processService.moveToErrorCommand(command, e.toString());
|
||||
logger.info("command {} process {} start...",
|
||||
command.getId(), processInstance.getId());
|
||||
masterExecService.execute(workflowExecuteThread);
|
||||
}
|
||||
} else {
|
||||
//indicate that no command ,sleep for 1s
|
||||
Thread.sleep(Constants.SLEEP_TIME_MILLIS);
|
||||
} catch (Exception e) {
|
||||
logger.error("scan command error ", e);
|
||||
processService.moveToErrorCommand(command, e.toString());
|
||||
}
|
||||
} finally {
|
||||
masterRegistryClient.releaseLock();
|
||||
} else {
|
||||
//indicate that no command ,sleep for 1s
|
||||
Thread.sleep(Constants.SLEEP_TIME_MILLIS);
|
||||
}
|
||||
}
|
||||
|
||||
private Command findOneCommand() {
|
||||
int pageNumber = 0;
|
||||
Command result = null;
|
||||
while (Stopper.isRunning()) {
|
||||
if (ServerNodeManager.MASTER_SIZE == 0) {
|
||||
return null;
|
||||
}
|
||||
List<Command> commandList = processService.findCommandPage(ServerNodeManager.MASTER_SIZE, pageNumber);
|
||||
if (commandList.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
for (Command command : commandList) {
|
||||
int slot = ServerNodeManager.getSlot();
|
||||
if (ServerNodeManager.MASTER_SIZE != 0
|
||||
&& command.getId() % ServerNodeManager.MASTER_SIZE == slot) {
|
||||
result = command;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result != null) {
|
||||
logger.info("find command {}, slot:{} :",
|
||||
result.getId(),
|
||||
ServerNodeManager.getSlot());
|
||||
break;
|
||||
}
|
||||
pageNumber += 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private String getLocalAddress() {
|
||||
return NetUtils.getAddr(masterConfig.getListenPort());
|
||||
}
|
||||
|
@ -1,230 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.server.master.runner;
|
||||
|
||||
import org.apache.dolphinscheduler.common.Constants;
|
||||
import org.apache.dolphinscheduler.common.enums.ExecutionStatus;
|
||||
import org.apache.dolphinscheduler.common.thread.Stopper;
|
||||
import org.apache.dolphinscheduler.common.utils.CollectionUtils;
|
||||
import org.apache.dolphinscheduler.common.utils.StringUtils;
|
||||
import org.apache.dolphinscheduler.dao.entity.TaskInstance;
|
||||
import org.apache.dolphinscheduler.remote.command.TaskKillRequestCommand;
|
||||
import org.apache.dolphinscheduler.remote.utils.Host;
|
||||
import org.apache.dolphinscheduler.server.master.cache.TaskInstanceCacheManager;
|
||||
import org.apache.dolphinscheduler.server.master.cache.impl.TaskInstanceCacheManagerImpl;
|
||||
import org.apache.dolphinscheduler.server.master.dispatch.context.ExecutionContext;
|
||||
import org.apache.dolphinscheduler.server.master.dispatch.enums.ExecutorType;
|
||||
import org.apache.dolphinscheduler.server.master.dispatch.executor.NettyExecutorManager;
|
||||
import org.apache.dolphinscheduler.service.bean.SpringApplicationContext;
|
||||
import org.apache.dolphinscheduler.service.registry.RegistryClient;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* master task exec thread
|
||||
*/
|
||||
public class MasterTaskExecThread extends MasterBaseTaskExecThread {
|
||||
|
||||
/**
|
||||
* taskInstance state manager
|
||||
*/
|
||||
private TaskInstanceCacheManager taskInstanceCacheManager;
|
||||
|
||||
/**
|
||||
* netty executor manager
|
||||
*/
|
||||
private NettyExecutorManager nettyExecutorManager;
|
||||
|
||||
|
||||
/**
|
||||
* zookeeper register center
|
||||
*/
|
||||
private RegistryClient registryClient;
|
||||
|
||||
/**
|
||||
* constructor of MasterTaskExecThread
|
||||
*
|
||||
* @param taskInstance task instance
|
||||
*/
|
||||
public MasterTaskExecThread(TaskInstance taskInstance) {
|
||||
super(taskInstance);
|
||||
this.taskInstanceCacheManager = SpringApplicationContext.getBean(TaskInstanceCacheManagerImpl.class);
|
||||
this.nettyExecutorManager = SpringApplicationContext.getBean(NettyExecutorManager.class);
|
||||
this.registryClient = RegistryClient.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* get task instance
|
||||
*
|
||||
* @return TaskInstance
|
||||
*/
|
||||
@Override
|
||||
public TaskInstance getTaskInstance() {
|
||||
return this.taskInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* whether already Killed,default false
|
||||
*/
|
||||
private boolean alreadyKilled = false;
|
||||
|
||||
/**
|
||||
* submit task instance and wait complete
|
||||
*
|
||||
* @return true is task quit is true
|
||||
*/
|
||||
@Override
|
||||
public Boolean submitWaitComplete() {
|
||||
Boolean result = false;
|
||||
this.taskInstance = submit();
|
||||
if (this.taskInstance == null) {
|
||||
logger.error("submit task instance to mysql and queue failed , please check and fix it");
|
||||
return result;
|
||||
}
|
||||
if (!this.taskInstance.getState().typeIsFinished()) {
|
||||
result = waitTaskQuit();
|
||||
}
|
||||
taskInstance.setEndTime(new Date());
|
||||
processService.updateTaskInstance(taskInstance);
|
||||
logger.info("task :{} id:{}, process id:{}, exec thread completed ",
|
||||
this.taskInstance.getName(), taskInstance.getId(), processInstance.getId());
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* polling db
|
||||
* <p>
|
||||
* wait task quit
|
||||
*
|
||||
* @return true if task quit success
|
||||
*/
|
||||
public Boolean waitTaskQuit() {
|
||||
// query new state
|
||||
taskInstance = processService.findTaskInstanceById(taskInstance.getId());
|
||||
logger.info("wait task: process id: {}, task id:{}, task name:{} complete",
|
||||
this.taskInstance.getProcessInstanceId(), this.taskInstance.getId(), this.taskInstance.getName());
|
||||
|
||||
while (Stopper.isRunning()) {
|
||||
try {
|
||||
if (this.processInstance == null) {
|
||||
logger.error("process instance not exists , master task exec thread exit");
|
||||
return true;
|
||||
}
|
||||
// task instance add queue , waiting worker to kill
|
||||
if (this.cancel || this.processInstance.getState() == ExecutionStatus.READY_STOP) {
|
||||
cancelTaskInstance();
|
||||
}
|
||||
if (processInstance.getState() == ExecutionStatus.READY_PAUSE) {
|
||||
pauseTask();
|
||||
}
|
||||
// task instance finished
|
||||
if (taskInstance.getState().typeIsFinished()) {
|
||||
// if task is final result , then remove taskInstance from cache
|
||||
taskInstanceCacheManager.removeByTaskInstanceId(taskInstance.getId());
|
||||
break;
|
||||
}
|
||||
if (checkTaskTimeout()) {
|
||||
this.checkTimeoutFlag = !alertTimeout();
|
||||
}
|
||||
// updateProcessInstance task instance
|
||||
//issue#5539 Check status of taskInstance from cache
|
||||
taskInstance = taskInstanceCacheManager.getByTaskInstanceId(taskInstance.getId());
|
||||
processInstance = processService.findProcessInstanceById(processInstance.getId());
|
||||
Thread.sleep(Constants.SLEEP_TIME_MILLIS);
|
||||
} catch (Exception e) {
|
||||
logger.error("exception", e);
|
||||
if (processInstance != null) {
|
||||
logger.error("wait task quit failed, instance id:{}, task id:{}",
|
||||
processInstance.getId(), taskInstance.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* pause task if task have not been dispatched to worker, do not dispatch anymore.
|
||||
*/
|
||||
public void pauseTask() {
|
||||
taskInstance = processService.findTaskInstanceById(taskInstance.getId());
|
||||
if (taskInstance == null) {
|
||||
return;
|
||||
}
|
||||
if (StringUtils.isBlank(taskInstance.getHost())) {
|
||||
taskInstance.setState(ExecutionStatus.PAUSE);
|
||||
taskInstance.setEndTime(new Date());
|
||||
processService.updateTaskInstance(taskInstance);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* task instance add queue , waiting worker to kill
|
||||
*/
|
||||
private void cancelTaskInstance() throws Exception {
|
||||
if (alreadyKilled) {
|
||||
return;
|
||||
}
|
||||
alreadyKilled = true;
|
||||
taskInstance = processService.findTaskInstanceById(taskInstance.getId());
|
||||
if (StringUtils.isBlank(taskInstance.getHost())) {
|
||||
taskInstance.setState(ExecutionStatus.KILL);
|
||||
taskInstance.setEndTime(new Date());
|
||||
processService.updateTaskInstance(taskInstance);
|
||||
return;
|
||||
}
|
||||
|
||||
TaskKillRequestCommand killCommand = new TaskKillRequestCommand();
|
||||
killCommand.setTaskInstanceId(taskInstance.getId());
|
||||
|
||||
ExecutionContext executionContext = new ExecutionContext(killCommand.convert2Command(), ExecutorType.WORKER);
|
||||
|
||||
Host host = Host.of(taskInstance.getHost());
|
||||
executionContext.setHost(host);
|
||||
|
||||
nettyExecutorManager.executeDirectly(executionContext);
|
||||
|
||||
logger.info("master kill taskInstance name :{} taskInstance id:{}",
|
||||
taskInstance.getName(), taskInstance.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* whether exists valid worker group
|
||||
*
|
||||
* @param taskInstanceWorkerGroup taskInstanceWorkerGroup
|
||||
* @return whether exists
|
||||
*/
|
||||
public Boolean existsValidWorkerGroup(String taskInstanceWorkerGroup) {
|
||||
Set<String> workerGroups = registryClient.getWorkerGroupDirectly();
|
||||
// not worker group
|
||||
if (CollectionUtils.isEmpty(workerGroups)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// has worker group , but not taskInstance assigned worker group
|
||||
if (!workerGroups.contains(taskInstanceWorkerGroup)) {
|
||||
return false;
|
||||
}
|
||||
Set<String> workers = registryClient.getWorkerGroupNodesDirectly(taskInstanceWorkerGroup);
|
||||
if (CollectionUtils.isEmpty(workers)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.server.master.runner;
|
||||
|
||||
import org.apache.dolphinscheduler.common.Constants;
|
||||
import org.apache.dolphinscheduler.common.enums.ExecutionStatus;
|
||||
import org.apache.dolphinscheduler.common.enums.StateEvent;
|
||||
import org.apache.dolphinscheduler.common.enums.StateEventType;
|
||||
import org.apache.dolphinscheduler.common.enums.TimeoutFlag;
|
||||
import org.apache.dolphinscheduler.common.thread.Stopper;
|
||||
import org.apache.dolphinscheduler.common.utils.DateUtils;
|
||||
import org.apache.dolphinscheduler.dao.entity.ProcessInstance;
|
||||
import org.apache.dolphinscheduler.dao.entity.TaskInstance;
|
||||
|
||||
import org.apache.hadoop.util.ThreadUtil;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* 1. timeout check wheel
|
||||
* 2. dependent task check wheel
|
||||
*/
|
||||
public class StateWheelExecuteThread extends Thread {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(StateWheelExecuteThread.class);
|
||||
|
||||
ConcurrentHashMap<Integer, ProcessInstance> processInstanceCheckList;
|
||||
ConcurrentHashMap<Integer, TaskInstance> taskInstanceCheckList;
|
||||
private ConcurrentHashMap<Integer, WorkflowExecuteThread> processInstanceExecMaps;
|
||||
|
||||
private int stateCheckIntervalSecs;
|
||||
|
||||
public StateWheelExecuteThread(ConcurrentHashMap<Integer, ProcessInstance> processInstances,
|
||||
ConcurrentHashMap<Integer, TaskInstance> taskInstances,
|
||||
ConcurrentHashMap<Integer, WorkflowExecuteThread> processInstanceExecMaps,
|
||||
int stateCheckIntervalSecs) {
|
||||
this.processInstanceCheckList = processInstances;
|
||||
this.taskInstanceCheckList = taskInstances;
|
||||
this.processInstanceExecMaps = processInstanceExecMaps;
|
||||
this.stateCheckIntervalSecs = stateCheckIntervalSecs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
logger.info("state wheel thread start");
|
||||
while (Stopper.isRunning()) {
|
||||
try {
|
||||
checkProcess();
|
||||
checkTask();
|
||||
} catch (Exception e) {
|
||||
logger.error("state wheel thread check error:", e);
|
||||
}
|
||||
ThreadUtil.sleepAtLeastIgnoreInterrupts(stateCheckIntervalSecs);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean addProcess(ProcessInstance processInstance) {
|
||||
this.processInstanceCheckList.put(processInstance.getId(), processInstance);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean addTask(TaskInstance taskInstance) {
|
||||
this.taskInstanceCheckList.put(taskInstance.getId(), taskInstance);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void checkTask() {
|
||||
if (taskInstanceCheckList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (TaskInstance taskInstance : this.taskInstanceCheckList.values()) {
|
||||
if (TimeoutFlag.OPEN == taskInstance.getTaskDefine().getTimeoutFlag()) {
|
||||
long timeRemain = DateUtils.getRemainTime(taskInstance.getStartTime(), taskInstance.getTaskDefine().getTimeout() * Constants.SEC_2_MINUTES_TIME_UNIT);
|
||||
if (0 <= timeRemain && processTimeout(taskInstance)) {
|
||||
taskInstanceCheckList.remove(taskInstance.getId());
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (taskInstance.isSubProcess() || taskInstance.isDependTask()) {
|
||||
processDependCheck(taskInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkProcess() {
|
||||
if (processInstanceCheckList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (ProcessInstance processInstance : this.processInstanceCheckList.values()) {
|
||||
|
||||
long timeRemain = DateUtils.getRemainTime(processInstance.getStartTime(), processInstance.getTimeout() * Constants.SEC_2_MINUTES_TIME_UNIT);
|
||||
if (0 <= timeRemain && processTimeout(processInstance)) {
|
||||
processInstanceCheckList.remove(processInstance.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void putEvent(StateEvent stateEvent) {
|
||||
|
||||
if (!processInstanceExecMaps.containsKey(stateEvent.getProcessInstanceId())) {
|
||||
return;
|
||||
}
|
||||
WorkflowExecuteThread workflowExecuteThread = this.processInstanceExecMaps.get(stateEvent.getProcessInstanceId());
|
||||
workflowExecuteThread.addStateEvent(stateEvent);
|
||||
}
|
||||
|
||||
private boolean processDependCheck(TaskInstance taskInstance) {
|
||||
StateEvent stateEvent = new StateEvent();
|
||||
stateEvent.setType(StateEventType.TASK_STATE_CHANGE);
|
||||
stateEvent.setProcessInstanceId(taskInstance.getProcessInstanceId());
|
||||
stateEvent.setTaskInstanceId(taskInstance.getId());
|
||||
stateEvent.setExecutionStatus(ExecutionStatus.RUNNING_EXECUTION);
|
||||
putEvent(stateEvent);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean processTimeout(TaskInstance taskInstance) {
|
||||
StateEvent stateEvent = new StateEvent();
|
||||
stateEvent.setType(StateEventType.TASK_TIMEOUT);
|
||||
stateEvent.setProcessInstanceId(taskInstance.getProcessInstanceId());
|
||||
stateEvent.setTaskInstanceId(taskInstance.getId());
|
||||
putEvent(stateEvent);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean processTimeout(ProcessInstance processInstance) {
|
||||
StateEvent stateEvent = new StateEvent();
|
||||
stateEvent.setType(StateEventType.PROCESS_TIMEOUT);
|
||||
stateEvent.setProcessInstanceId(processInstance.getId());
|
||||
putEvent(stateEvent);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -1,181 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dolphinscheduler.server.master.runner;
|
||||
|
||||
import org.apache.dolphinscheduler.common.Constants;
|
||||
import org.apache.dolphinscheduler.common.enums.ExecutionStatus;
|
||||
import org.apache.dolphinscheduler.common.thread.Stopper;
|
||||
import org.apache.dolphinscheduler.dao.entity.ProcessInstance;
|
||||
import org.apache.dolphinscheduler.dao.entity.TaskInstance;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* subflow task exec thread
|
||||
*/
|
||||
public class SubProcessTaskExecThread extends MasterBaseTaskExecThread {
|
||||
|
||||
/**
|
||||
* sub process instance
|
||||
*/
|
||||
private ProcessInstance subProcessInstance;
|
||||
|
||||
/**
|
||||
* sub process task exec thread
|
||||
* @param taskInstance task instance
|
||||
*/
|
||||
public SubProcessTaskExecThread(TaskInstance taskInstance){
|
||||
super(taskInstance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean submitWaitComplete() {
|
||||
|
||||
Boolean result = false;
|
||||
try{
|
||||
// submit task instance
|
||||
this.taskInstance = submit();
|
||||
|
||||
if(taskInstance == null){
|
||||
logger.error("sub work flow submit task instance to mysql and queue failed , please check and fix it");
|
||||
return result;
|
||||
}
|
||||
setTaskInstanceState();
|
||||
waitTaskQuit();
|
||||
subProcessInstance = processService.findSubProcessInstance(processInstance.getId(), taskInstance.getId());
|
||||
|
||||
// at the end of the subflow , the task state is changed to the subflow state
|
||||
if(subProcessInstance != null){
|
||||
if(subProcessInstance.getState() == ExecutionStatus.STOP){
|
||||
this.taskInstance.setState(ExecutionStatus.KILL);
|
||||
}else{
|
||||
this.taskInstance.setState(subProcessInstance.getState());
|
||||
}
|
||||
}
|
||||
taskInstance.setEndTime(new Date());
|
||||
processService.updateTaskInstance(taskInstance);
|
||||
logger.info("subflow task :{} id:{}, process id:{}, exec thread completed ",
|
||||
this.taskInstance.getName(),taskInstance.getId(), processInstance.getId() );
|
||||
result = true;
|
||||
|
||||
}catch (Exception e){
|
||||
logger.error("exception: ",e);
|
||||
if (null != taskInstance) {
|
||||
logger.error("wait task quit failed, instance id:{}, task id:{}",
|
||||
processInstance.getId(), taskInstance.getId());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* set task instance state
|
||||
* @return
|
||||
*/
|
||||
private boolean setTaskInstanceState(){
|
||||
subProcessInstance = processService.findSubProcessInstance(processInstance.getId(), taskInstance.getId());
|
||||
if(subProcessInstance == null || taskInstance.getState().typeIsFinished()){
|
||||
return false;
|
||||
}
|
||||
|
||||
taskInstance.setState(ExecutionStatus.RUNNING_EXECUTION);
|
||||
taskInstance.setStartTime(new Date());
|
||||
processService.updateTaskInstance(taskInstance);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* updateProcessInstance parent state
|
||||
*/
|
||||
private void updateParentProcessState(){
|
||||
ProcessInstance parentProcessInstance = processService.findProcessInstanceById(this.processInstance.getId());
|
||||
|
||||
if(parentProcessInstance == null){
|
||||
logger.error("parent work flow instance is null , please check it! work flow id {}", processInstance.getId());
|
||||
return;
|
||||
}
|
||||
this.processInstance.setState(parentProcessInstance.getState());
|
||||
}
|
||||
|
||||
/**
|
||||
* wait task quit
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
private void waitTaskQuit() throws InterruptedException {
|
||||
|
||||
logger.info("wait sub work flow: {} complete", this.taskInstance.getName());
|
||||
|
||||
if (taskInstance.getState().typeIsFinished()) {
|
||||
logger.info("sub work flow task {} already complete. task state:{}, parent work flow instance state:{}",
|
||||
this.taskInstance.getName(),
|
||||
this.taskInstance.getState(),
|
||||
this.processInstance.getState());
|
||||
return;
|
||||
}
|
||||
while (Stopper.isRunning()) {
|
||||
// waiting for subflow process instance establishment
|
||||
if (subProcessInstance == null) {
|
||||
Thread.sleep(Constants.SLEEP_TIME_MILLIS);
|
||||
if(!setTaskInstanceState()){
|
||||
continue;
|
||||
}
|
||||
}
|
||||
subProcessInstance = processService.findProcessInstanceById(subProcessInstance.getId());
|
||||
if (checkTaskTimeout()) {
|
||||
this.checkTimeoutFlag = !alertTimeout();
|
||||
handleTimeoutFailed();
|
||||
}
|
||||
updateParentProcessState();
|
||||
if (subProcessInstance.getState().typeIsFinished()){
|
||||
break;
|
||||
}
|
||||
if(this.processInstance.getState() == ExecutionStatus.READY_PAUSE){
|
||||
// parent process "ready to pause" , child process "pause"
|
||||
pauseSubProcess();
|
||||
}else if(this.cancel || this.processInstance.getState() == ExecutionStatus.READY_STOP){
|
||||
// parent Process "Ready to Cancel" , subflow "Cancel"
|
||||
stopSubProcess();
|
||||
}
|
||||
Thread.sleep(Constants.SLEEP_TIME_MILLIS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* stop sub process
|
||||
*/
|
||||
private void stopSubProcess() {
|
||||
if(subProcessInstance.getState() == ExecutionStatus.STOP ||
|
||||
subProcessInstance.getState() == ExecutionStatus.READY_STOP){
|
||||
return;
|
||||
}
|
||||
subProcessInstance.setState(ExecutionStatus.READY_STOP);
|
||||
processService.updateProcessInstance(subProcessInstance);
|
||||
}
|
||||
|
||||
/**
|
||||
* pause sub process
|
||||
*/
|
||||
private void pauseSubProcess() {
|
||||
if(subProcessInstance.getState() == ExecutionStatus.PAUSE ||
|
||||
subProcessInstance.getState() == ExecutionStatus.READY_PAUSE){
|
||||
return;
|
||||
}
|
||||
subProcessInstance.setState(ExecutionStatus.READY_PAUSE);
|
||||
processService.updateProcessInstance(subProcessInstance);
|
||||
}
|
||||
}
|
@ -32,27 +32,38 @@ import org.apache.dolphinscheduler.common.enums.ExecutionStatus;
|
||||
import org.apache.dolphinscheduler.common.enums.FailureStrategy;
|
||||
import org.apache.dolphinscheduler.common.enums.Flag;
|
||||
import org.apache.dolphinscheduler.common.enums.Priority;
|
||||
import org.apache.dolphinscheduler.common.enums.StateEvent;
|
||||
import org.apache.dolphinscheduler.common.enums.StateEventType;
|
||||
import org.apache.dolphinscheduler.common.enums.TaskDependType;
|
||||
import org.apache.dolphinscheduler.common.enums.TaskTimeoutStrategy;
|
||||
import org.apache.dolphinscheduler.common.enums.TimeoutFlag;
|
||||
import org.apache.dolphinscheduler.common.graph.DAG;
|
||||
import org.apache.dolphinscheduler.common.model.TaskNode;
|
||||
import org.apache.dolphinscheduler.common.model.TaskNodeRelation;
|
||||
import org.apache.dolphinscheduler.common.process.ProcessDag;
|
||||
import org.apache.dolphinscheduler.common.process.Property;
|
||||
import org.apache.dolphinscheduler.common.thread.Stopper;
|
||||
import org.apache.dolphinscheduler.common.thread.ThreadUtils;
|
||||
import org.apache.dolphinscheduler.common.utils.CollectionUtils;
|
||||
import org.apache.dolphinscheduler.common.utils.DateUtils;
|
||||
import org.apache.dolphinscheduler.common.utils.JSONUtils;
|
||||
import org.apache.dolphinscheduler.common.utils.NetUtils;
|
||||
import org.apache.dolphinscheduler.common.utils.OSUtils;
|
||||
import org.apache.dolphinscheduler.common.utils.ParameterUtils;
|
||||
import org.apache.dolphinscheduler.common.utils.StringUtils;
|
||||
import org.apache.dolphinscheduler.dao.entity.ProcessDefinition;
|
||||
import org.apache.dolphinscheduler.dao.entity.ProcessInstance;
|
||||
import org.apache.dolphinscheduler.dao.entity.ProjectUser;
|
||||
import org.apache.dolphinscheduler.dao.entity.Schedule;
|
||||
import org.apache.dolphinscheduler.dao.entity.TaskDefinition;
|
||||
import org.apache.dolphinscheduler.dao.entity.TaskInstance;
|
||||
import org.apache.dolphinscheduler.dao.utils.DagHelper;
|
||||
import org.apache.dolphinscheduler.remote.NettyRemotingClient;
|
||||
import org.apache.dolphinscheduler.remote.command.HostUpdateCommand;
|
||||
import org.apache.dolphinscheduler.remote.utils.Host;
|
||||
import org.apache.dolphinscheduler.server.master.config.MasterConfig;
|
||||
import org.apache.dolphinscheduler.server.master.dispatch.executor.NettyExecutorManager;
|
||||
import org.apache.dolphinscheduler.server.master.runner.task.ITaskProcessor;
|
||||
import org.apache.dolphinscheduler.server.master.runner.task.TaskAction;
|
||||
import org.apache.dolphinscheduler.server.master.runner.task.TaskProcessorFactory;
|
||||
import org.apache.dolphinscheduler.service.alert.ProcessAlertManager;
|
||||
import org.apache.dolphinscheduler.service.process.ProcessService;
|
||||
import org.apache.dolphinscheduler.service.quartz.cron.CronUtils;
|
||||
@ -68,27 +79,29 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.collect.HashBasedTable;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Table;
|
||||
|
||||
/**
|
||||
* master exec thread,split dag
|
||||
*/
|
||||
public class MasterExecThread implements Runnable {
|
||||
public class WorkflowExecuteThread implements Runnable {
|
||||
|
||||
/**
|
||||
* logger of MasterExecThread
|
||||
* logger of WorkflowExecuteThread
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(MasterExecThread.class);
|
||||
private static final Logger logger = LoggerFactory.getLogger(WorkflowExecuteThread.class);
|
||||
/**
|
||||
* runing TaskNode
|
||||
*/
|
||||
private final Map<MasterBaseTaskExecThread, Future<Boolean>> activeTaskNode = new ConcurrentHashMap<>();
|
||||
private final Map<Integer, ITaskProcessor> activeTaskProcessorMaps = new ConcurrentHashMap<>();
|
||||
/**
|
||||
* task exec service
|
||||
*/
|
||||
@ -165,7 +178,8 @@ public class MasterExecThread implements Runnable {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private NettyRemotingClient nettyRemotingClient;
|
||||
private NettyExecutorManager nettyExecutorManager;
|
||||
|
||||
/**
|
||||
* submit post node
|
||||
*
|
||||
@ -173,18 +187,31 @@ public class MasterExecThread implements Runnable {
|
||||
*/
|
||||
private Map<String, Object> propToValue = new ConcurrentHashMap<>();
|
||||
|
||||
private ConcurrentLinkedQueue<StateEvent> stateEvents = new ConcurrentLinkedQueue<>();
|
||||
|
||||
private List<Date> complementListDate = Lists.newLinkedList();
|
||||
|
||||
private Table<Integer, Long, TaskInstance> taskInstanceHashMap = HashBasedTable.create();
|
||||
private ProcessDefinition processDefinition;
|
||||
private String key;
|
||||
|
||||
private ConcurrentHashMap<Integer, TaskInstance> taskTimeoutCheckList;
|
||||
|
||||
|
||||
/**
|
||||
* constructor of MasterExecThread
|
||||
* constructor of WorkflowExecuteThread
|
||||
*
|
||||
* @param processInstance processInstance
|
||||
* @param processService processService
|
||||
* @param nettyRemotingClient nettyRemotingClient
|
||||
* @param processInstance processInstance
|
||||
* @param processService processService
|
||||
* @param nettyExecutorManager nettyExecutorManager
|
||||
* @param taskTimeoutCheckList
|
||||
*/
|
||||
public MasterExecThread(ProcessInstance processInstance
|
||||
public WorkflowExecuteThread(ProcessInstance processInstance
|
||||
, ProcessService processService
|
||||
, NettyRemotingClient nettyRemotingClient
|
||||
, NettyExecutorManager nettyExecutorManager
|
||||
, ProcessAlertManager processAlertManager
|
||||
, MasterConfig masterConfig) {
|
||||
, MasterConfig masterConfig
|
||||
, ConcurrentHashMap<Integer, TaskInstance> taskTimeoutCheckList) {
|
||||
this.processService = processService;
|
||||
|
||||
this.processInstance = processInstance;
|
||||
@ -192,149 +219,256 @@ public class MasterExecThread implements Runnable {
|
||||
int masterTaskExecNum = masterConfig.getMasterExecTaskNum();
|
||||
this.taskExecService = ThreadUtils.newDaemonFixedThreadExecutor("Master-Task-Exec-Thread",
|
||||
masterTaskExecNum);
|
||||
this.nettyRemotingClient = nettyRemotingClient;
|
||||
this.nettyExecutorManager = nettyExecutorManager;
|
||||
this.processAlertManager = processAlertManager;
|
||||
this.taskTimeoutCheckList = taskTimeoutCheckList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
// process instance is null
|
||||
if (processInstance == null) {
|
||||
logger.info("process instance is not exists");
|
||||
return;
|
||||
}
|
||||
|
||||
// check to see if it's done
|
||||
if (processInstance.getState().typeIsFinished()) {
|
||||
logger.info("process instance is done : {}", processInstance.getId());
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (processInstance.isComplementData() && Flag.NO == processInstance.getIsSubProcess()) {
|
||||
// sub process complement data
|
||||
executeComplementProcess();
|
||||
} else {
|
||||
// execute flow
|
||||
executeProcess();
|
||||
}
|
||||
startProcess();
|
||||
handleEvents();
|
||||
} catch (Exception e) {
|
||||
logger.error("master exec thread exception", e);
|
||||
logger.error("process execute failed, process id:{}", processInstance.getId());
|
||||
processInstance.setState(ExecutionStatus.FAILURE);
|
||||
processInstance.setEndTime(new Date());
|
||||
processService.updateProcessInstance(processInstance);
|
||||
} finally {
|
||||
taskExecService.shutdown();
|
||||
logger.error("handler error:", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* execute process
|
||||
*
|
||||
* @throws Exception exception
|
||||
*/
|
||||
private void executeProcess() throws Exception {
|
||||
prepareProcess();
|
||||
runProcess();
|
||||
endProcess();
|
||||
private void handleEvents() {
|
||||
while (this.stateEvents.size() > 0) {
|
||||
|
||||
try {
|
||||
StateEvent stateEvent = this.stateEvents.peek();
|
||||
if (stateEventHandler(stateEvent)) {
|
||||
this.stateEvents.remove(stateEvent);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("state handle error:", e);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* execute complement process
|
||||
*
|
||||
* @throws Exception exception
|
||||
*/
|
||||
private void executeComplementProcess() throws Exception {
|
||||
|
||||
Map<String, String> cmdParam = JSONUtils.toMap(processInstance.getCommandParam());
|
||||
|
||||
Date startDate = DateUtils.getScheduleDate(cmdParam.get(CMDPARAM_COMPLEMENT_DATA_START_DATE));
|
||||
Date endDate = DateUtils.getScheduleDate(cmdParam.get(CMDPARAM_COMPLEMENT_DATA_END_DATE));
|
||||
processService.saveProcessInstance(processInstance);
|
||||
|
||||
// get schedules
|
||||
List<Schedule> schedules = processService.queryReleaseSchedulerListByProcessDefinitionCode(
|
||||
processInstance.getProcessDefinitionCode());
|
||||
List<Date> listDate = Lists.newLinkedList();
|
||||
if (!CollectionUtils.isEmpty(schedules)) {
|
||||
for (Schedule schedule : schedules) {
|
||||
listDate.addAll(CronUtils.getSelfFireDateList(startDate, endDate, schedule.getCrontab()));
|
||||
}
|
||||
}
|
||||
// get first fire date
|
||||
Iterator<Date> iterator = null;
|
||||
Date scheduleDate;
|
||||
if (!CollectionUtils.isEmpty(listDate)) {
|
||||
iterator = listDate.iterator();
|
||||
scheduleDate = iterator.next();
|
||||
processInstance.setScheduleTime(scheduleDate);
|
||||
processService.updateProcessInstance(processInstance);
|
||||
} else {
|
||||
scheduleDate = processInstance.getScheduleTime();
|
||||
if (scheduleDate == null) {
|
||||
scheduleDate = startDate;
|
||||
}
|
||||
public String getKey() {
|
||||
if (StringUtils.isNotEmpty(key)
|
||||
|| this.processDefinition == null) {
|
||||
return key;
|
||||
}
|
||||
|
||||
while (Stopper.isRunning()) {
|
||||
logger.info("process {} start to complement {} data", processInstance.getId(), DateUtils.dateToString(scheduleDate));
|
||||
// prepare dag and other info
|
||||
prepareProcess();
|
||||
key = String.format("{}_{}_{}",
|
||||
this.processDefinition.getCode(),
|
||||
this.processDefinition.getVersion(),
|
||||
this.processInstance.getId());
|
||||
return key;
|
||||
}
|
||||
|
||||
if (dag == null) {
|
||||
logger.error("process {} dag is null, please check out parameters",
|
||||
processInstance.getId());
|
||||
processInstance.setState(ExecutionStatus.SUCCESS);
|
||||
processService.updateProcessInstance(processInstance);
|
||||
return;
|
||||
}
|
||||
public boolean addStateEvent(StateEvent stateEvent) {
|
||||
if (processInstance.getId() != stateEvent.getProcessInstanceId()) {
|
||||
logger.info("state event would be abounded :{}", stateEvent.toString());
|
||||
return false;
|
||||
}
|
||||
this.stateEvents.add(stateEvent);
|
||||
return true;
|
||||
}
|
||||
|
||||
// execute process ,waiting for end
|
||||
runProcess();
|
||||
public int eventSize() {
|
||||
return this.stateEvents.size();
|
||||
}
|
||||
|
||||
endProcess();
|
||||
// process instance failure ,no more complements
|
||||
if (!processInstance.getState().typeIsSuccess()) {
|
||||
logger.info("process {} state {}, complement not completely!", processInstance.getId(), processInstance.getState());
|
||||
public ProcessInstance getProcessInstance() {
|
||||
return this.processInstance;
|
||||
}
|
||||
|
||||
private boolean stateEventHandler(StateEvent stateEvent) {
|
||||
logger.info("process event: {}", stateEvent.toString());
|
||||
|
||||
if (!checkStateEvent(stateEvent)) {
|
||||
return false;
|
||||
}
|
||||
boolean result = false;
|
||||
switch (stateEvent.getType()) {
|
||||
case PROCESS_STATE_CHANGE:
|
||||
result = processStateChangeHandler(stateEvent);
|
||||
break;
|
||||
}
|
||||
// current process instance success ,next execute
|
||||
if (null == iterator) {
|
||||
// loop by day
|
||||
scheduleDate = DateUtils.getSomeDay(scheduleDate, 1);
|
||||
if (scheduleDate.after(endDate)) {
|
||||
// all success
|
||||
logger.info("process {} complement completely!", processInstance.getId());
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// loop by schedule date
|
||||
if (!iterator.hasNext()) {
|
||||
// all success
|
||||
logger.info("process {} complement completely!", processInstance.getId());
|
||||
break;
|
||||
}
|
||||
scheduleDate = iterator.next();
|
||||
}
|
||||
// flow end
|
||||
// execute next process instance complement data
|
||||
processInstance.setScheduleTime(scheduleDate);
|
||||
if (cmdParam.containsKey(Constants.CMD_PARAM_RECOVERY_START_NODE_STRING)) {
|
||||
cmdParam.remove(Constants.CMD_PARAM_RECOVERY_START_NODE_STRING);
|
||||
processInstance.setCommandParam(JSONUtils.toJsonString(cmdParam));
|
||||
}
|
||||
case TASK_STATE_CHANGE:
|
||||
result = taskStateChangeHandler(stateEvent);
|
||||
break;
|
||||
case PROCESS_TIMEOUT:
|
||||
result = processTimeout();
|
||||
break;
|
||||
case TASK_TIMEOUT:
|
||||
result = taskTimeout(stateEvent);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
processInstance.setState(ExecutionStatus.RUNNING_EXECUTION);
|
||||
processInstance.setGlobalParams(ParameterUtils.curingGlobalParams(
|
||||
processInstance.getProcessDefinition().getGlobalParamMap(),
|
||||
processInstance.getProcessDefinition().getGlobalParamList(),
|
||||
CommandType.COMPLEMENT_DATA, processInstance.getScheduleTime()));
|
||||
processInstance.setId(0);
|
||||
processInstance.setStartTime(new Date());
|
||||
processInstance.setEndTime(null);
|
||||
if (result) {
|
||||
this.stateEvents.remove(stateEvent);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean taskTimeout(StateEvent stateEvent) {
|
||||
|
||||
if (taskInstanceHashMap.containsRow(stateEvent.getTaskInstanceId())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
TaskInstance taskInstance = taskInstanceHashMap
|
||||
.row(stateEvent.getTaskInstanceId())
|
||||
.values()
|
||||
.iterator().next();
|
||||
|
||||
if (TimeoutFlag.CLOSE == taskInstance.getTaskDefine().getTimeoutFlag()) {
|
||||
return true;
|
||||
}
|
||||
TaskTimeoutStrategy taskTimeoutStrategy = taskInstance.getTaskDefine().getTimeoutNotifyStrategy();
|
||||
if (TaskTimeoutStrategy.FAILED == taskTimeoutStrategy) {
|
||||
ITaskProcessor taskProcessor = activeTaskProcessorMaps.get(stateEvent.getTaskInstanceId());
|
||||
taskProcessor.action(TaskAction.TIMEOUT);
|
||||
return false;
|
||||
} else {
|
||||
processAlertManager.sendTaskTimeoutAlert(processInstance, taskInstance, taskInstance.getTaskDefine());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean processTimeout() {
|
||||
this.processAlertManager.sendProcessTimeoutAlert(this.processInstance, this.processDefinition);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean taskStateChangeHandler(StateEvent stateEvent) {
|
||||
TaskInstance task = processService.findTaskInstanceById(stateEvent.getTaskInstanceId());
|
||||
if (stateEvent.getExecutionStatus().typeIsFinished()) {
|
||||
taskFinished(task);
|
||||
} else if (activeTaskProcessorMaps.containsKey(stateEvent.getTaskInstanceId())) {
|
||||
ITaskProcessor iTaskProcessor = activeTaskProcessorMaps.get(stateEvent.getTaskInstanceId());
|
||||
iTaskProcessor.run();
|
||||
|
||||
if (iTaskProcessor.taskState().typeIsFinished()) {
|
||||
task = processService.findTaskInstanceById(stateEvent.getTaskInstanceId());
|
||||
taskFinished(task);
|
||||
}
|
||||
} else {
|
||||
logger.error("state handler error: {}", stateEvent.toString());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void taskFinished(TaskInstance task) {
|
||||
logger.info("work flow {} task {} state:{} ",
|
||||
processInstance.getId(),
|
||||
task.getId(),
|
||||
task.getState());
|
||||
if (task.taskCanRetry()) {
|
||||
addTaskToStandByList(task);
|
||||
return;
|
||||
}
|
||||
ProcessInstance processInstance = processService.findProcessInstanceById(this.processInstance.getId());
|
||||
completeTaskList.put(task.getName(), task);
|
||||
activeTaskProcessorMaps.remove(task.getId());
|
||||
taskTimeoutCheckList.remove(task.getId());
|
||||
if (task.getState().typeIsSuccess()) {
|
||||
processInstance.setVarPool(task.getVarPool());
|
||||
processService.saveProcessInstance(processInstance);
|
||||
submitPostNode(task.getName());
|
||||
} else if (task.getState().typeIsFailure()) {
|
||||
if (task.isConditionsTask()
|
||||
|| DagHelper.haveConditionsAfterNode(task.getName(), dag)) {
|
||||
submitPostNode(task.getName());
|
||||
} else {
|
||||
errorTaskList.put(task.getName(), task);
|
||||
if (processInstance.getFailureStrategy() == FailureStrategy.END) {
|
||||
killAllTasks();
|
||||
}
|
||||
}
|
||||
}
|
||||
this.updateProcessInstanceState();
|
||||
}
|
||||
|
||||
private boolean checkStateEvent(StateEvent stateEvent) {
|
||||
if (this.processInstance.getId() != stateEvent.getProcessInstanceId()) {
|
||||
logger.error("mismatch process instance id: {}, state event:{}",
|
||||
this.processInstance.getId(),
|
||||
stateEvent.toString());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean processStateChangeHandler(StateEvent stateEvent) {
|
||||
try {
|
||||
logger.info("process:{} state {} change to {}", processInstance.getId(), processInstance.getState(), stateEvent.getExecutionStatus());
|
||||
processInstance = processService.findProcessInstanceById(this.processInstance.getId());
|
||||
if (processComplementData()) {
|
||||
return true;
|
||||
}
|
||||
if (stateEvent.getExecutionStatus().typeIsFinished()) {
|
||||
endProcess();
|
||||
}
|
||||
if (stateEvent.getExecutionStatus() == ExecutionStatus.READY_STOP) {
|
||||
killAllTasks();
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
logger.error("process state change error:", e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean processComplementData() throws Exception {
|
||||
if (!needComplementProcess()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Date scheduleDate = processInstance.getScheduleTime();
|
||||
if (scheduleDate == null) {
|
||||
scheduleDate = complementListDate.get(0);
|
||||
} else if (processInstance.getState().typeIsFinished()) {
|
||||
endProcess();
|
||||
int index = complementListDate.indexOf(scheduleDate);
|
||||
if (index >= complementListDate.size() - 1 || !processInstance.getState().typeIsSuccess()) {
|
||||
// complement data ends || no success
|
||||
return false;
|
||||
}
|
||||
scheduleDate = complementListDate.get(index + 1);
|
||||
//the next process complement
|
||||
processInstance.setId(0);
|
||||
}
|
||||
processInstance.setScheduleTime(scheduleDate);
|
||||
Map<String, String> cmdParam = JSONUtils.toMap(processInstance.getCommandParam());
|
||||
if (cmdParam.containsKey(Constants.CMD_PARAM_RECOVERY_START_NODE_STRING)) {
|
||||
cmdParam.remove(Constants.CMD_PARAM_RECOVERY_START_NODE_STRING);
|
||||
processInstance.setCommandParam(JSONUtils.toJsonString(cmdParam));
|
||||
}
|
||||
processInstance.setState(ExecutionStatus.RUNNING_EXECUTION);
|
||||
processInstance.setGlobalParams(ParameterUtils.curingGlobalParams(
|
||||
processDefinition.getGlobalParamMap(),
|
||||
processDefinition.getGlobalParamList(),
|
||||
CommandType.COMPLEMENT_DATA, processInstance.getScheduleTime()));
|
||||
processInstance.setStartTime(new Date());
|
||||
processInstance.setEndTime(null);
|
||||
processService.saveProcessInstance(processInstance);
|
||||
this.taskInstanceHashMap.clear();
|
||||
startProcess();
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean needComplementProcess() {
|
||||
if (processInstance.isComplementData()
|
||||
&& Flag.NO == processInstance.getIsSubProcess()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void startProcess() throws Exception {
|
||||
buildFlowDag();
|
||||
if (this.taskInstanceHashMap.size() == 0) {
|
||||
initTaskQueue();
|
||||
submitPostNode(null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -357,6 +491,7 @@ public class MasterExecThread implements Runnable {
|
||||
* process end handle
|
||||
*/
|
||||
private void endProcess() {
|
||||
this.stateEvents.clear();
|
||||
processInstance.setEndTime(new Date());
|
||||
processService.updateProcessInstance(processInstance);
|
||||
if (processInstance.getState().typeIsWaitingThread()) {
|
||||
@ -373,6 +508,11 @@ public class MasterExecThread implements Runnable {
|
||||
* @throws Exception exception
|
||||
*/
|
||||
private void buildFlowDag() throws Exception {
|
||||
if (this.dag != null) {
|
||||
return;
|
||||
}
|
||||
processDefinition = processService.findProcessDefinition(processInstance.getProcessDefinitionCode(),
|
||||
processInstance.getProcessDefinitionVersion());
|
||||
recoverNodeIdList = getStartTaskInstanceList(processInstance.getCommandParam());
|
||||
List<TaskNode> taskNodeList =
|
||||
processService.genTaskNodeList(processInstance.getProcessDefinitionCode(), processInstance.getProcessDefinitionVersion(), new HashMap<>());
|
||||
@ -400,8 +540,9 @@ public class MasterExecThread implements Runnable {
|
||||
*/
|
||||
private void initTaskQueue() {
|
||||
|
||||
|
||||
taskFailedSubmit = false;
|
||||
activeTaskNode.clear();
|
||||
activeTaskProcessorMaps.clear();
|
||||
dependFailedTask.clear();
|
||||
completeTaskList.clear();
|
||||
errorTaskList.clear();
|
||||
@ -417,6 +558,22 @@ public class MasterExecThread implements Runnable {
|
||||
errorTaskList.put(task.getName(), task);
|
||||
}
|
||||
}
|
||||
|
||||
if (complementListDate.size() == 0 && needComplementProcess()) {
|
||||
Map<String, String> cmdParam = JSONUtils.toMap(processInstance.getCommandParam());
|
||||
Date startDate = DateUtils.getScheduleDate(cmdParam.get(CMDPARAM_COMPLEMENT_DATA_START_DATE));
|
||||
Date endDate = DateUtils.getScheduleDate(cmdParam.get(CMDPARAM_COMPLEMENT_DATA_END_DATE));
|
||||
if (startDate.after(endDate)) {
|
||||
Date tmp = startDate;
|
||||
startDate = endDate;
|
||||
endDate = tmp;
|
||||
}
|
||||
List<Schedule> schedules = processService.queryReleaseSchedulerListByProcessDefinitionCode(processInstance.getProcessDefinitionCode());
|
||||
complementListDate.addAll(CronUtils.getSelfFireDateList(startDate, endDate, schedules));
|
||||
logger.info(" process definition code:{} complement data: {}",
|
||||
processInstance.getProcessDefinitionCode(), complementListDate.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -426,26 +583,80 @@ public class MasterExecThread implements Runnable {
|
||||
* @return TaskInstance
|
||||
*/
|
||||
private TaskInstance submitTaskExec(TaskInstance taskInstance) {
|
||||
MasterBaseTaskExecThread abstractExecThread = null;
|
||||
if (taskInstance.isSubProcess()) {
|
||||
abstractExecThread = new SubProcessTaskExecThread(taskInstance);
|
||||
} else if (taskInstance.isDependTask()) {
|
||||
abstractExecThread = new DependentTaskExecThread(taskInstance);
|
||||
} else if (taskInstance.isConditionsTask()) {
|
||||
abstractExecThread = new ConditionsTaskExecThread(taskInstance);
|
||||
} else {
|
||||
abstractExecThread = new MasterTaskExecThread(taskInstance);
|
||||
try {
|
||||
ITaskProcessor taskProcessor = TaskProcessorFactory.getTaskProcessor(taskInstance.getTaskType());
|
||||
if (taskInstance.getState() == ExecutionStatus.RUNNING_EXECUTION
|
||||
&& taskProcessor.getType().equalsIgnoreCase(Constants.COMMON_TASK_TYPE)) {
|
||||
notifyProcessHostUpdate(taskInstance);
|
||||
}
|
||||
boolean submit = taskProcessor.submit(taskInstance, processInstance, masterConfig.getMasterTaskCommitRetryTimes(), masterConfig.getMasterTaskCommitInterval());
|
||||
if (submit) {
|
||||
this.taskInstanceHashMap.put(taskInstance.getId(), taskInstance.getTaskCode(), taskInstance);
|
||||
activeTaskProcessorMaps.put(taskInstance.getId(), taskProcessor);
|
||||
taskProcessor.run();
|
||||
addTimeoutCheck(taskInstance);
|
||||
TaskDefinition taskDefinition = processService.findTaskDefinition(
|
||||
taskInstance.getTaskCode(),
|
||||
taskInstance.getTaskDefinitionVersion());
|
||||
taskInstance.setTaskDefine(taskDefinition);
|
||||
if (taskProcessor.taskState().typeIsFinished()) {
|
||||
StateEvent stateEvent = new StateEvent();
|
||||
stateEvent.setProcessInstanceId(this.processInstance.getId());
|
||||
stateEvent.setTaskInstanceId(taskInstance.getId());
|
||||
stateEvent.setExecutionStatus(taskProcessor.taskState());
|
||||
stateEvent.setType(StateEventType.TASK_STATE_CHANGE);
|
||||
this.stateEvents.add(stateEvent);
|
||||
}
|
||||
return taskInstance;
|
||||
} else {
|
||||
logger.error("process id:{} name:{} submit standby task id:{} name:{} failed!",
|
||||
processInstance.getId(), processInstance.getName(),
|
||||
taskInstance.getId(), taskInstance.getName());
|
||||
return null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("submit standby task error", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyProcessHostUpdate(TaskInstance taskInstance) {
|
||||
if (StringUtils.isEmpty(taskInstance.getHost())) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
HostUpdateCommand hostUpdateCommand = new HostUpdateCommand();
|
||||
hostUpdateCommand.setProcessHost(NetUtils.getAddr(masterConfig.getListenPort()));
|
||||
hostUpdateCommand.setTaskInstanceId(taskInstance.getId());
|
||||
Host host = new Host(taskInstance.getHost());
|
||||
nettyExecutorManager.doExecute(host, hostUpdateCommand.convert2Command());
|
||||
} catch (Exception e) {
|
||||
logger.error("notify process host update", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void addTimeoutCheck(TaskInstance taskInstance) {
|
||||
|
||||
TaskDefinition taskDefinition = processService.findTaskDefinition(
|
||||
taskInstance.getTaskCode(),
|
||||
taskInstance.getTaskDefinitionVersion()
|
||||
);
|
||||
taskInstance.setTaskDefine(taskDefinition);
|
||||
if (TimeoutFlag.OPEN == taskDefinition.getTimeoutFlag()) {
|
||||
this.taskTimeoutCheckList.put(taskInstance.getId(), taskInstance);
|
||||
return;
|
||||
}
|
||||
if (taskInstance.isDependTask() || taskInstance.isSubProcess()) {
|
||||
this.taskTimeoutCheckList.put(taskInstance.getId(), taskInstance);
|
||||
}
|
||||
Future<Boolean> future = taskExecService.submit(abstractExecThread);
|
||||
activeTaskNode.putIfAbsent(abstractExecThread, future);
|
||||
return abstractExecThread.getTaskInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* find task instance in db.
|
||||
* in case submit more than one same name task in the same time.
|
||||
*
|
||||
* @param taskCode task code
|
||||
* @param taskCode task code
|
||||
* @param taskVersion task version
|
||||
* @return TaskInstance
|
||||
*/
|
||||
@ -454,6 +665,7 @@ public class MasterExecThread implements Runnable {
|
||||
for (TaskInstance taskInstance : taskInstanceList) {
|
||||
if (taskInstance.getTaskCode() == taskCode && taskInstance.getTaskDefinitionVersion() == taskVersion) {
|
||||
return taskInstance;
|
||||
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@ -463,7 +675,7 @@ public class MasterExecThread implements Runnable {
|
||||
* encapsulation task
|
||||
*
|
||||
* @param processInstance process instance
|
||||
* @param taskNode taskNode
|
||||
* @param taskNode taskNode
|
||||
* @return TaskInstance
|
||||
*/
|
||||
private TaskInstance createTaskInstance(ProcessInstance processInstance, TaskNode taskNode) {
|
||||
@ -523,9 +735,9 @@ public class MasterExecThread implements Runnable {
|
||||
return taskInstance;
|
||||
}
|
||||
|
||||
public void getPreVarPool(TaskInstance taskInstance, Set<String> preTask) {
|
||||
Map<String,Property> allProperty = new HashMap<>();
|
||||
Map<String,TaskInstance> allTaskInstance = new HashMap<>();
|
||||
public void getPreVarPool(TaskInstance taskInstance, Set<String> preTask) {
|
||||
Map<String, Property> allProperty = new HashMap<>();
|
||||
Map<String, TaskInstance> allTaskInstance = new HashMap<>();
|
||||
if (CollectionUtils.isNotEmpty(preTask)) {
|
||||
for (String preTaskName : preTask) {
|
||||
TaskInstance preTaskInstance = completeTaskList.get(preTaskName);
|
||||
@ -563,17 +775,17 @@ public class MasterExecThread implements Runnable {
|
||||
TaskInstance otherTask = allTaskInstance.get(proName);
|
||||
if (otherTask.getEndTime().getTime() > preTaskInstance.getEndTime().getTime()) {
|
||||
allProperty.put(proName, thisProperty);
|
||||
allTaskInstance.put(proName,preTaskInstance);
|
||||
allTaskInstance.put(proName, preTaskInstance);
|
||||
} else {
|
||||
allProperty.put(proName, otherPro);
|
||||
}
|
||||
} else {
|
||||
allProperty.put(proName, thisProperty);
|
||||
allTaskInstance.put(proName,preTaskInstance);
|
||||
allTaskInstance.put(proName, preTaskInstance);
|
||||
}
|
||||
} else {
|
||||
allProperty.put(proName, thisProperty);
|
||||
allTaskInstance.put(proName,preTaskInstance);
|
||||
allTaskInstance.put(proName, preTaskInstance);
|
||||
}
|
||||
}
|
||||
|
||||
@ -582,16 +794,18 @@ public class MasterExecThread implements Runnable {
|
||||
List<TaskInstance> taskInstances = new ArrayList<>();
|
||||
for (String taskNode : submitTaskNodeList) {
|
||||
TaskNode taskNodeObject = dag.getNode(taskNode);
|
||||
taskInstances.add(createTaskInstance(processInstance, taskNodeObject));
|
||||
if (taskInstanceHashMap.containsColumn(taskNodeObject.getCode())) {
|
||||
continue;
|
||||
}
|
||||
TaskInstance task = createTaskInstance(processInstance, taskNodeObject);
|
||||
taskInstances.add(task);
|
||||
}
|
||||
|
||||
// if previous node success , post node submit
|
||||
for (TaskInstance task : taskInstances) {
|
||||
|
||||
if (readyToSubmitTaskQueue.contains(task)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (completeTaskList.containsKey(task.getName())) {
|
||||
logger.info("task {} has already run success", task.getName());
|
||||
continue;
|
||||
@ -602,6 +816,8 @@ public class MasterExecThread implements Runnable {
|
||||
addTaskToStandByList(task);
|
||||
}
|
||||
}
|
||||
submitStandByTask();
|
||||
updateProcessInstanceState();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -724,7 +940,7 @@ public class MasterExecThread implements Runnable {
|
||||
return true;
|
||||
}
|
||||
if (processInstance.getFailureStrategy() == FailureStrategy.CONTINUE) {
|
||||
return readyToSubmitTaskQueue.size() == 0 || activeTaskNode.size() == 0;
|
||||
return readyToSubmitTaskQueue.size() == 0 || activeTaskProcessorMaps.size() == 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@ -766,13 +982,13 @@ public class MasterExecThread implements Runnable {
|
||||
/**
|
||||
* generate the latest process instance status by the tasks state
|
||||
*
|
||||
* @param instance
|
||||
* @return process instance execution status
|
||||
*/
|
||||
private ExecutionStatus getProcessInstanceState() {
|
||||
ProcessInstance instance = processService.findProcessInstanceById(processInstance.getId());
|
||||
private ExecutionStatus getProcessInstanceState(ProcessInstance instance) {
|
||||
ExecutionStatus state = instance.getState();
|
||||
|
||||
if (activeTaskNode.size() > 0 || hasRetryTaskInStandBy()) {
|
||||
if (activeTaskProcessorMaps.size() > 0 || hasRetryTaskInStandBy()) {
|
||||
// active task and retry task exists
|
||||
return runningState(state);
|
||||
}
|
||||
@ -864,7 +1080,8 @@ public class MasterExecThread implements Runnable {
|
||||
* after each batch of tasks is executed, the status of the process instance is updated
|
||||
*/
|
||||
private void updateProcessInstanceState() {
|
||||
ExecutionStatus state = getProcessInstanceState();
|
||||
ProcessInstance instance = processService.findProcessInstanceById(processInstance.getId());
|
||||
ExecutionStatus state = getProcessInstanceState(instance);
|
||||
if (processInstance.getState() != state) {
|
||||
logger.info(
|
||||
"work flow process instance [id: {}, name:{}], state change from {} to {}, cmd type: {}",
|
||||
@ -872,11 +1089,14 @@ public class MasterExecThread implements Runnable {
|
||||
processInstance.getState(), state,
|
||||
processInstance.getCommandType());
|
||||
|
||||
ProcessInstance instance = processService.findProcessInstanceById(processInstance.getId());
|
||||
instance.setState(state);
|
||||
instance.setProcessDefinition(processInstance.getProcessDefinition());
|
||||
processService.updateProcessInstance(instance);
|
||||
processInstance = instance;
|
||||
StateEvent stateEvent = new StateEvent();
|
||||
stateEvent.setExecutionStatus(processInstance.getState());
|
||||
stateEvent.setProcessInstanceId(this.processInstance.getId());
|
||||
stateEvent.setType(StateEventType.PROCESS_STATE_CHANGE);
|
||||
this.processStateChangeHandler(stateEvent);
|
||||
}
|
||||
}
|
||||
|
||||
@ -910,11 +1130,15 @@ public class MasterExecThread implements Runnable {
|
||||
* @param taskInstance task instance
|
||||
*/
|
||||
private void removeTaskFromStandbyList(TaskInstance taskInstance) {
|
||||
logger.info("remove task from stand by list: {}", taskInstance.getName());
|
||||
logger.info("remove task from stand by list, id: {} name:{}",
|
||||
taskInstance.getId(),
|
||||
taskInstance.getName());
|
||||
try {
|
||||
readyToSubmitTaskQueue.remove(taskInstance);
|
||||
} catch (Exception e) {
|
||||
logger.error("remove task instance from readyToSubmitTaskQueue error, taskName: {}", taskInstance.getName(), e);
|
||||
logger.error("remove task instance from readyToSubmitTaskQueue error, task id:{}, Name: {}",
|
||||
taskInstance.getId(),
|
||||
taskInstance.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -932,129 +1156,6 @@ public class MasterExecThread implements Runnable {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* submit and watch the tasks, until the work flow stop
|
||||
*/
|
||||
private void runProcess() {
|
||||
// submit start node
|
||||
submitPostNode(null);
|
||||
boolean sendTimeWarning = false;
|
||||
while (!processInstance.isProcessInstanceStop() && Stopper.isRunning()) {
|
||||
|
||||
// send warning email if process time out.
|
||||
if (!sendTimeWarning && checkProcessTimeOut(processInstance)) {
|
||||
processAlertManager.sendProcessTimeoutAlert(processInstance,
|
||||
processService.findProcessDefinition(processInstance.getProcessDefinitionCode(),
|
||||
processInstance.getProcessDefinitionVersion()));
|
||||
sendTimeWarning = true;
|
||||
}
|
||||
for (Map.Entry<MasterBaseTaskExecThread, Future<Boolean>> entry : activeTaskNode.entrySet()) {
|
||||
Future<Boolean> future = entry.getValue();
|
||||
TaskInstance task = entry.getKey().getTaskInstance();
|
||||
|
||||
if (!future.isDone()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// node monitor thread complete
|
||||
task = this.processService.findTaskInstanceById(task.getId());
|
||||
|
||||
if (task == null) {
|
||||
this.taskFailedSubmit = true;
|
||||
activeTaskNode.remove(entry.getKey());
|
||||
continue;
|
||||
}
|
||||
|
||||
// node monitor thread complete
|
||||
if (task.getState().typeIsFinished()) {
|
||||
activeTaskNode.remove(entry.getKey());
|
||||
}
|
||||
|
||||
logger.info("task :{}, id:{} complete, state is {} ",
|
||||
task.getName(), task.getId(), task.getState());
|
||||
// node success , post node submit
|
||||
if (task.getState() == ExecutionStatus.SUCCESS) {
|
||||
processInstance = processService.findProcessInstanceById(processInstance.getId());
|
||||
processInstance.setVarPool(task.getVarPool());
|
||||
processService.updateProcessInstance(processInstance);
|
||||
completeTaskList.put(task.getName(), task);
|
||||
submitPostNode(task.getName());
|
||||
continue;
|
||||
}
|
||||
// node fails, retry first, and then execute the failure process
|
||||
if (task.getState().typeIsFailure()) {
|
||||
if (task.getState() == ExecutionStatus.NEED_FAULT_TOLERANCE) {
|
||||
this.recoverToleranceFaultTaskList.add(task);
|
||||
}
|
||||
if (task.taskCanRetry()) {
|
||||
addTaskToStandByList(task);
|
||||
} else {
|
||||
completeTaskList.put(task.getName(), task);
|
||||
if (task.isConditionsTask()
|
||||
|| DagHelper.haveConditionsAfterNode(task.getName(), dag)) {
|
||||
submitPostNode(task.getName());
|
||||
} else {
|
||||
errorTaskList.put(task.getName(), task);
|
||||
if (processInstance.getFailureStrategy() == FailureStrategy.END) {
|
||||
killTheOtherTasks();
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// other status stop/pause
|
||||
completeTaskList.put(task.getName(), task);
|
||||
}
|
||||
// send alert
|
||||
if (CollectionUtils.isNotEmpty(this.recoverToleranceFaultTaskList)) {
|
||||
processAlertManager.sendAlertWorkerToleranceFault(processInstance, recoverToleranceFaultTaskList);
|
||||
this.recoverToleranceFaultTaskList.clear();
|
||||
}
|
||||
// updateProcessInstance completed task status
|
||||
// failure priority is higher than pause
|
||||
// if a task fails, other suspended tasks need to be reset kill
|
||||
// check if there exists forced success nodes in errorTaskList
|
||||
if (errorTaskList.size() > 0) {
|
||||
for (Map.Entry<String, TaskInstance> entry : completeTaskList.entrySet()) {
|
||||
TaskInstance completeTask = entry.getValue();
|
||||
if (completeTask.getState() == ExecutionStatus.PAUSE) {
|
||||
completeTask.setState(ExecutionStatus.KILL);
|
||||
completeTaskList.put(entry.getKey(), completeTask);
|
||||
processService.updateTaskInstance(completeTask);
|
||||
}
|
||||
}
|
||||
for (Map.Entry<String, TaskInstance> entry : errorTaskList.entrySet()) {
|
||||
TaskInstance errorTask = entry.getValue();
|
||||
TaskInstance currentTask = processService.findTaskInstanceById(errorTask.getId());
|
||||
if (currentTask == null) {
|
||||
continue;
|
||||
}
|
||||
// for nodes that have been forced success
|
||||
if (errorTask.getState().typeIsFailure() && currentTask.getState().equals(ExecutionStatus.FORCED_SUCCESS)) {
|
||||
// update state in this thread and remove from errorTaskList
|
||||
errorTask.setState(currentTask.getState());
|
||||
logger.info("task: {} has been forced success, remove it from error task list", errorTask.getName());
|
||||
errorTaskList.remove(errorTask.getName());
|
||||
// submit post nodes
|
||||
submitPostNode(errorTask.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (canSubmitTaskToQueue()) {
|
||||
submitStandByTask();
|
||||
}
|
||||
try {
|
||||
Thread.sleep(Constants.SLEEP_TIME_MILLIS);
|
||||
} catch (InterruptedException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
updateProcessInstanceState();
|
||||
}
|
||||
|
||||
logger.info("process:{} end, state :{}", processInstance.getId(), processInstance.getState());
|
||||
}
|
||||
|
||||
/**
|
||||
* whether check process time out
|
||||
*
|
||||
@ -1084,28 +1185,30 @@ public class MasterExecThread implements Runnable {
|
||||
/**
|
||||
* close the on going tasks
|
||||
*/
|
||||
private void killTheOtherTasks() {
|
||||
|
||||
private void killAllTasks() {
|
||||
logger.info("kill called on process instance id: {}, num: {}", processInstance.getId(),
|
||||
activeTaskNode.size());
|
||||
for (Map.Entry<MasterBaseTaskExecThread, Future<Boolean>> entry : activeTaskNode.entrySet()) {
|
||||
MasterBaseTaskExecThread taskExecThread = entry.getKey();
|
||||
Future<Boolean> future = entry.getValue();
|
||||
|
||||
TaskInstance taskInstance = taskExecThread.getTaskInstance();
|
||||
taskInstance = processService.findTaskInstanceById(taskInstance.getId());
|
||||
if (taskInstance != null && taskInstance.getState().typeIsFinished()) {
|
||||
activeTaskProcessorMaps.size());
|
||||
for (int taskId : activeTaskProcessorMaps.keySet()) {
|
||||
TaskInstance taskInstance = processService.findTaskInstanceById(taskId);
|
||||
if (taskInstance == null || taskInstance.getState().typeIsFinished()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!future.isDone()) {
|
||||
// record kill info
|
||||
logger.info("kill process instance, id: {}, task: {}", processInstance.getId(), taskExecThread.getTaskInstance().getId());
|
||||
|
||||
// kill node
|
||||
taskExecThread.kill();
|
||||
ITaskProcessor taskProcessor = activeTaskProcessorMaps.get(taskId);
|
||||
taskProcessor.action(TaskAction.STOP);
|
||||
if (taskProcessor.taskState().typeIsFinished()) {
|
||||
StateEvent stateEvent = new StateEvent();
|
||||
stateEvent.setType(StateEventType.TASK_STATE_CHANGE);
|
||||
stateEvent.setProcessInstanceId(this.processInstance.getId());
|
||||
stateEvent.setTaskInstanceId(taskInstance.getId());
|
||||
stateEvent.setExecutionStatus(taskProcessor.taskState());
|
||||
this.addStateEvent(stateEvent);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public boolean workFlowFinish() {
|
||||
return this.processInstance.getState().typeIsFinished();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1139,6 +1242,9 @@ public class MasterExecThread implements Runnable {
|
||||
int length = readyToSubmitTaskQueue.size();
|
||||
for (int i = 0; i < length; i++) {
|
||||
TaskInstance task = readyToSubmitTaskQueue.peek();
|
||||
if (task == null) {
|
||||
continue;
|
||||
}
|
||||
// stop tasks which is retrying if forced success happens
|
||||
if (task.taskCanRetry()) {
|
||||
TaskInstance retryTask = processService.findTaskInstanceById(task.getId());
|
||||
@ -1160,8 +1266,12 @@ public class MasterExecThread implements Runnable {
|
||||
DependResult dependResult = getDependResultForTask(task);
|
||||
if (DependResult.SUCCESS == dependResult) {
|
||||
if (retryTaskIntervalOverTime(task)) {
|
||||
submitTaskExec(task);
|
||||
removeTaskFromStandbyList(task);
|
||||
TaskInstance taskInstance = submitTaskExec(task);
|
||||
if (taskInstance == null) {
|
||||
this.taskFailedSubmit = true;
|
||||
} else {
|
||||
removeTaskFromStandbyList(task);
|
||||
}
|
||||
}
|
||||
} else if (DependResult.FAILED == dependResult) {
|
||||
// if the dependency fails, the current node is not submitted and the state changes to failure.
|
||||
@ -1263,10 +1373,10 @@ public class MasterExecThread implements Runnable {
|
||||
/**
|
||||
* generate flow dag
|
||||
*
|
||||
* @param totalTaskNodeList total task node list
|
||||
* @param startNodeNameList start node name list
|
||||
* @param totalTaskNodeList total task node list
|
||||
* @param startNodeNameList start node name list
|
||||
* @param recoveryNodeNameList recovery node name list
|
||||
* @param depNodeType depend node type
|
||||
* @param depNodeType depend node type
|
||||
* @return ProcessDag process dag
|
||||
* @throws Exception exception
|
||||
*/
|
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.server.master.runner.task;
|
||||
|
||||
import org.apache.dolphinscheduler.dao.entity.ProcessInstance;
|
||||
import org.apache.dolphinscheduler.dao.entity.TaskInstance;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public abstract class BaseTaskProcessor implements ITaskProcessor {
|
||||
|
||||
protected Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
protected boolean killed = false;
|
||||
|
||||
protected boolean paused = false;
|
||||
|
||||
protected boolean timeout = false;
|
||||
|
||||
protected TaskInstance taskInstance = null;
|
||||
|
||||
protected ProcessInstance processInstance;
|
||||
|
||||
/**
|
||||
* pause task, common tasks donot need this.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected abstract boolean pauseTask();
|
||||
|
||||
/**
|
||||
* kill task, all tasks need to realize this function
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected abstract boolean killTask();
|
||||
|
||||
/**
|
||||
* task timeout process
|
||||
* @return
|
||||
*/
|
||||
protected abstract boolean taskTimeout();
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean action(TaskAction taskAction) {
|
||||
|
||||
switch (taskAction) {
|
||||
case STOP:
|
||||
return stop();
|
||||
case PAUSE:
|
||||
return pause();
|
||||
case TIMEOUT:
|
||||
return timeout();
|
||||
default:
|
||||
logger.error("unknown task action: {}", taskAction.toString());
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean timeout() {
|
||||
if (timeout) {
|
||||
return true;
|
||||
}
|
||||
timeout = taskTimeout();
|
||||
return timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
protected boolean pause() {
|
||||
if (paused) {
|
||||
return true;
|
||||
}
|
||||
paused = pauseTask();
|
||||
return paused;
|
||||
}
|
||||
|
||||
protected boolean stop() {
|
||||
if (killed) {
|
||||
return true;
|
||||
}
|
||||
killed = killTask();
|
||||
return killed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.server.master.runner.task;
|
||||
|
||||
import org.apache.dolphinscheduler.common.Constants;
|
||||
|
||||
public class CommonTaskProcessFactory implements ITaskProcessFactory {
|
||||
@Override
|
||||
public String type() {
|
||||
return Constants.COMMON_TASK_TYPE;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITaskProcessor create() {
|
||||
return new CommonTaskProcessor();
|
||||
}
|
||||
}
|
@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.server.master.runner.task;
|
||||
|
||||
import org.apache.dolphinscheduler.common.Constants;
|
||||
import org.apache.dolphinscheduler.common.enums.ExecutionStatus;
|
||||
import org.apache.dolphinscheduler.common.utils.JSONUtils;
|
||||
import org.apache.dolphinscheduler.dao.entity.ProcessInstance;
|
||||
import org.apache.dolphinscheduler.dao.entity.TaskInstance;
|
||||
import org.apache.dolphinscheduler.remote.command.TaskKillRequestCommand;
|
||||
import org.apache.dolphinscheduler.remote.utils.Host;
|
||||
import org.apache.dolphinscheduler.server.master.config.MasterConfig;
|
||||
import org.apache.dolphinscheduler.server.master.dispatch.context.ExecutionContext;
|
||||
import org.apache.dolphinscheduler.server.master.dispatch.enums.ExecutorType;
|
||||
import org.apache.dolphinscheduler.server.master.dispatch.exceptions.ExecuteException;
|
||||
import org.apache.dolphinscheduler.server.master.dispatch.executor.NettyExecutorManager;
|
||||
import org.apache.dolphinscheduler.service.bean.SpringApplicationContext;
|
||||
import org.apache.dolphinscheduler.service.process.ProcessService;
|
||||
import org.apache.dolphinscheduler.service.queue.TaskPriority;
|
||||
import org.apache.dolphinscheduler.service.queue.TaskPriorityQueue;
|
||||
import org.apache.dolphinscheduler.service.queue.TaskPriorityQueueImpl;
|
||||
|
||||
import org.apache.logging.log4j.util.Strings;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* common task processor
|
||||
*/
|
||||
public class CommonTaskProcessor extends BaseTaskProcessor {
|
||||
|
||||
@Autowired
|
||||
private TaskPriorityQueue taskUpdateQueue;
|
||||
|
||||
@Autowired
|
||||
MasterConfig masterConfig;
|
||||
|
||||
@Autowired
|
||||
NettyExecutorManager nettyExecutorManager;
|
||||
|
||||
/**
|
||||
* logger of MasterBaseTaskExecThread
|
||||
*/
|
||||
protected Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
protected ProcessService processService = SpringApplicationContext.getBean(ProcessService.class);
|
||||
|
||||
@Override
|
||||
public boolean submit(TaskInstance task, ProcessInstance processInstance, int maxRetryTimes, int commitInterval) {
|
||||
this.processInstance = processInstance;
|
||||
this.taskInstance = processService.submitTask(task, maxRetryTimes, commitInterval);
|
||||
|
||||
if (this.taskInstance == null) {
|
||||
return false;
|
||||
}
|
||||
dispatchTask(taskInstance, processInstance);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExecutionStatus taskState() {
|
||||
return this.taskInstance.getState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean taskTimeout() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* common task cannot be paused
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
protected boolean pauseTask() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return Constants.COMMON_TASK_TYPE;
|
||||
}
|
||||
|
||||
private boolean dispatchTask(TaskInstance taskInstance, ProcessInstance processInstance) {
|
||||
|
||||
try {
|
||||
if (taskUpdateQueue == null) {
|
||||
this.initQueue();
|
||||
}
|
||||
if (taskInstance.getState().typeIsFinished()) {
|
||||
logger.info(String.format("submit task , but task [%s] state [%s] is already finished. ", taskInstance.getName(), taskInstance.getState().toString()));
|
||||
return true;
|
||||
}
|
||||
// task cannot be submitted because its execution state is RUNNING or DELAY.
|
||||
if (taskInstance.getState() == ExecutionStatus.RUNNING_EXECUTION
|
||||
|| taskInstance.getState() == ExecutionStatus.DELAY_EXECUTION) {
|
||||
logger.info("submit task, but the status of the task {} is already running or delayed.", taskInstance.getName());
|
||||
return true;
|
||||
}
|
||||
logger.info("task ready to submit: {}", taskInstance);
|
||||
|
||||
TaskPriority taskPriority = new TaskPriority(processInstance.getProcessInstancePriority().getCode(),
|
||||
processInstance.getId(), taskInstance.getProcessInstancePriority().getCode(),
|
||||
taskInstance.getId(), org.apache.dolphinscheduler.common.Constants.DEFAULT_WORKER_GROUP);
|
||||
taskUpdateQueue.put(taskPriority);
|
||||
logger.info(String.format("master submit success, task : %s", taskInstance.getName()));
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
logger.error("submit task Exception: ", e);
|
||||
logger.error("task error : %s", JSONUtils.toJsonString(taskInstance));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void initQueue() {
|
||||
this.taskUpdateQueue = SpringApplicationContext.getBean(TaskPriorityQueueImpl.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean killTask() {
|
||||
|
||||
try {
|
||||
taskInstance = processService.findTaskInstanceById(taskInstance.getId());
|
||||
if (taskInstance == null) {
|
||||
return true;
|
||||
}
|
||||
if (taskInstance.getState().typeIsFinished()) {
|
||||
return true;
|
||||
}
|
||||
if (Strings.isBlank(taskInstance.getHost())) {
|
||||
taskInstance.setState(ExecutionStatus.KILL);
|
||||
taskInstance.setEndTime(new Date());
|
||||
processService.updateTaskInstance(taskInstance);
|
||||
return true;
|
||||
}
|
||||
|
||||
TaskKillRequestCommand killCommand = new TaskKillRequestCommand();
|
||||
killCommand.setTaskInstanceId(taskInstance.getId());
|
||||
|
||||
ExecutionContext executionContext = new ExecutionContext(killCommand.convert2Command(), ExecutorType.WORKER);
|
||||
|
||||
Host host = Host.of(taskInstance.getHost());
|
||||
executionContext.setHost(host);
|
||||
|
||||
nettyExecutorManager.executeDirectly(executionContext);
|
||||
} catch (ExecuteException e) {
|
||||
logger.error("kill task error:", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
logger.info("master kill taskInstance name :{} taskInstance id:{}",
|
||||
taskInstance.getName(), taskInstance.getId());
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.server.master.runner.task;
|
||||
|
||||
import org.apache.dolphinscheduler.common.enums.TaskType;
|
||||
|
||||
public class ConditionTaskProcessFactory implements ITaskProcessFactory {
|
||||
@Override
|
||||
public String type() {
|
||||
return TaskType.CONDITIONS.getDesc();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITaskProcessor create() {
|
||||
return new ConditionTaskProcessor();
|
||||
}
|
||||
}
|
@ -14,19 +14,27 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dolphinscheduler.server.master.runner;
|
||||
|
||||
package org.apache.dolphinscheduler.server.master.runner.task;
|
||||
|
||||
import org.apache.dolphinscheduler.common.Constants;
|
||||
import org.apache.dolphinscheduler.common.enums.DependResult;
|
||||
import org.apache.dolphinscheduler.common.enums.ExecutionStatus;
|
||||
import org.apache.dolphinscheduler.common.enums.TaskTimeoutStrategy;
|
||||
import org.apache.dolphinscheduler.common.enums.TaskType;
|
||||
import org.apache.dolphinscheduler.common.model.DependentItem;
|
||||
import org.apache.dolphinscheduler.common.model.DependentTaskModel;
|
||||
import org.apache.dolphinscheduler.common.task.dependent.DependentParameters;
|
||||
import org.apache.dolphinscheduler.common.utils.DependentUtils;
|
||||
import org.apache.dolphinscheduler.common.utils.LoggerUtils;
|
||||
import org.apache.dolphinscheduler.common.utils.NetUtils;
|
||||
import org.apache.dolphinscheduler.dao.entity.ProcessInstance;
|
||||
import org.apache.dolphinscheduler.dao.entity.TaskDefinition;
|
||||
import org.apache.dolphinscheduler.dao.entity.TaskInstance;
|
||||
import org.apache.dolphinscheduler.server.master.config.MasterConfig;
|
||||
import org.apache.dolphinscheduler.server.utils.LogUtils;
|
||||
import org.apache.dolphinscheduler.service.bean.SpringApplicationContext;
|
||||
import org.apache.dolphinscheduler.service.process.ProcessService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
@ -36,55 +44,121 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ConditionsTaskExecThread extends MasterBaseTaskExecThread {
|
||||
/**
|
||||
* condition task processor
|
||||
*/
|
||||
public class ConditionTaskProcessor extends BaseTaskProcessor {
|
||||
|
||||
/**
|
||||
* dependent parameters
|
||||
*/
|
||||
private DependentParameters dependentParameters;
|
||||
|
||||
ProcessInstance processInstance;
|
||||
|
||||
/**
|
||||
* condition result
|
||||
*/
|
||||
private DependResult conditionResult = DependResult.WAITING;
|
||||
|
||||
/**
|
||||
* complete task map
|
||||
*/
|
||||
private Map<String, ExecutionStatus> completeTaskList = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* condition result
|
||||
*/
|
||||
private DependResult conditionResult;
|
||||
protected ProcessService processService = SpringApplicationContext.getBean(ProcessService.class);
|
||||
MasterConfig masterConfig = SpringApplicationContext.getBean(MasterConfig.class);
|
||||
|
||||
/**
|
||||
* constructor of MasterBaseTaskExecThread
|
||||
*
|
||||
* @param taskInstance task instance
|
||||
*/
|
||||
public ConditionsTaskExecThread(TaskInstance taskInstance) {
|
||||
super(taskInstance);
|
||||
taskInstance.setStartTime(new Date());
|
||||
}
|
||||
private TaskDefinition taskDefinition;
|
||||
|
||||
@Override
|
||||
public Boolean submitWaitComplete() {
|
||||
try {
|
||||
this.taskInstance = submit();
|
||||
logger = LoggerFactory.getLogger(LoggerUtils.buildTaskId(LoggerUtils.TASK_LOGGER_INFO_PREFIX,
|
||||
processInstance.getProcessDefinitionCode(),
|
||||
processInstance.getProcessDefinitionVersion(),
|
||||
taskInstance.getProcessInstanceId(),
|
||||
taskInstance.getId()));
|
||||
String threadLoggerInfoName = String.format(Constants.TASK_LOG_INFO_FORMAT, processService.formatTaskAppId(this.taskInstance));
|
||||
Thread.currentThread().setName(threadLoggerInfoName);
|
||||
initTaskParameters();
|
||||
logger.info("dependent task start");
|
||||
waitTaskQuit();
|
||||
updateTaskState();
|
||||
} catch (Exception e) {
|
||||
logger.error("conditions task run exception", e);
|
||||
public boolean submit(TaskInstance task, ProcessInstance processInstance, int masterTaskCommitRetryTimes, int masterTaskCommitInterval) {
|
||||
this.processInstance = processInstance;
|
||||
this.taskInstance = processService.submitTask(task, masterTaskCommitRetryTimes, masterTaskCommitInterval);
|
||||
|
||||
if (this.taskInstance == null) {
|
||||
return false;
|
||||
}
|
||||
taskDefinition = processService.findTaskDefinition(
|
||||
taskInstance.getTaskCode(), taskInstance.getTaskDefinitionVersion()
|
||||
);
|
||||
|
||||
logger = LoggerFactory.getLogger(LoggerUtils.buildTaskId(LoggerUtils.TASK_LOGGER_INFO_PREFIX,
|
||||
processInstance.getProcessDefinitionCode(),
|
||||
processInstance.getProcessDefinitionVersion(),
|
||||
taskInstance.getProcessInstanceId(),
|
||||
taskInstance.getId()));
|
||||
String threadLoggerInfoName = String.format(Constants.TASK_LOG_INFO_FORMAT, processService.formatTaskAppId(this.taskInstance));
|
||||
Thread.currentThread().setName(threadLoggerInfoName);
|
||||
initTaskParameters();
|
||||
logger.info("dependent task start");
|
||||
endTask();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void waitTaskQuit() {
|
||||
@Override
|
||||
public ExecutionStatus taskState() {
|
||||
return this.taskInstance.getState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (conditionResult.equals(DependResult.WAITING)) {
|
||||
setConditionResult();
|
||||
} else {
|
||||
endTask();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean pauseTask() {
|
||||
this.taskInstance.setState(ExecutionStatus.PAUSE);
|
||||
this.taskInstance.setEndTime(new Date());
|
||||
processService.saveTaskInstance(taskInstance);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean taskTimeout() {
|
||||
TaskTimeoutStrategy taskTimeoutStrategy =
|
||||
taskDefinition.getTimeoutNotifyStrategy();
|
||||
if (taskTimeoutStrategy == TaskTimeoutStrategy.WARN) {
|
||||
return true;
|
||||
}
|
||||
logger.info("condition task {} timeout, strategy {} ",
|
||||
taskInstance.getId(), taskTimeoutStrategy.getDescp());
|
||||
conditionResult = DependResult.FAILED;
|
||||
endTask();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean killTask() {
|
||||
this.taskInstance.setState(ExecutionStatus.KILL);
|
||||
this.taskInstance.setEndTime(new Date());
|
||||
processService.saveTaskInstance(taskInstance);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return TaskType.CONDITIONS.getDesc();
|
||||
}
|
||||
|
||||
private void initTaskParameters() {
|
||||
taskInstance.setLogPath(LogUtils.getTaskLogPath(processInstance.getProcessDefinitionCode(),
|
||||
processInstance.getProcessDefinitionVersion(),
|
||||
taskInstance.getProcessInstanceId(),
|
||||
taskInstance.getId()));
|
||||
this.taskInstance.setHost(NetUtils.getAddr(masterConfig.getListenPort()));
|
||||
taskInstance.setState(ExecutionStatus.RUNNING_EXECUTION);
|
||||
taskInstance.setStartTime(new Date());
|
||||
this.processService.saveTaskInstance(taskInstance);
|
||||
this.dependentParameters = taskInstance.getDependency();
|
||||
}
|
||||
|
||||
private void setConditionResult() {
|
||||
|
||||
List<TaskInstance> taskInstances = processService.findValidTaskListByProcessId(taskInstance.getProcessInstanceId());
|
||||
for (TaskInstance task : taskInstances) {
|
||||
completeTaskList.putIfAbsent(task.getName(), task.getState());
|
||||
@ -103,32 +177,6 @@ public class ConditionsTaskExecThread extends MasterBaseTaskExecThread {
|
||||
logger.info("the conditions task depend result : {}", conditionResult);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private void updateTaskState() {
|
||||
ExecutionStatus status;
|
||||
if (this.cancel) {
|
||||
status = ExecutionStatus.KILL;
|
||||
} else {
|
||||
status = (conditionResult == DependResult.SUCCESS) ? ExecutionStatus.SUCCESS : ExecutionStatus.FAILURE;
|
||||
}
|
||||
taskInstance.setState(status);
|
||||
taskInstance.setEndTime(new Date());
|
||||
processService.updateTaskInstance(taskInstance);
|
||||
}
|
||||
|
||||
private void initTaskParameters() {
|
||||
taskInstance.setLogPath(LogUtils.getTaskLogPath(processInstance.getProcessDefinitionCode(),
|
||||
processInstance.getProcessDefinitionVersion(),
|
||||
taskInstance.getProcessInstanceId(),
|
||||
taskInstance.getId()));
|
||||
this.taskInstance.setHost(NetUtils.getAddr(masterConfig.getListenPort()));
|
||||
taskInstance.setState(ExecutionStatus.RUNNING_EXECUTION);
|
||||
taskInstance.setStartTime(new Date());
|
||||
this.processService.saveTaskInstance(taskInstance);
|
||||
this.dependentParameters = taskInstance.getDependency();
|
||||
}
|
||||
|
||||
/**
|
||||
* depend result for depend item
|
||||
@ -151,4 +199,13 @@ public class ConditionsTaskExecThread extends MasterBaseTaskExecThread {
|
||||
return dependResult;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private void endTask() {
|
||||
ExecutionStatus status = (conditionResult == DependResult.SUCCESS) ? ExecutionStatus.SUCCESS : ExecutionStatus.FAILURE;
|
||||
taskInstance.setState(status);
|
||||
taskInstance.setEndTime(new Date());
|
||||
processService.updateTaskInstance(taskInstance);
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.server.master.runner.task;
|
||||
|
||||
import org.apache.dolphinscheduler.common.enums.TaskType;
|
||||
|
||||
public class DependentTaskProcessFactory implements ITaskProcessFactory {
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return TaskType.DEPENDENT.getDesc();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITaskProcessor create() {
|
||||
return new DependentTaskProcessor();
|
||||
}
|
||||
}
|
@ -15,22 +15,26 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.server.master.runner;
|
||||
package org.apache.dolphinscheduler.server.master.runner.task;
|
||||
|
||||
import static org.apache.dolphinscheduler.common.Constants.DEPENDENT_SPLIT;
|
||||
|
||||
import org.apache.dolphinscheduler.common.Constants;
|
||||
import org.apache.dolphinscheduler.common.enums.DependResult;
|
||||
import org.apache.dolphinscheduler.common.enums.ExecutionStatus;
|
||||
import org.apache.dolphinscheduler.common.enums.TaskTimeoutStrategy;
|
||||
import org.apache.dolphinscheduler.common.enums.TaskType;
|
||||
import org.apache.dolphinscheduler.common.model.DependentTaskModel;
|
||||
import org.apache.dolphinscheduler.common.task.dependent.DependentParameters;
|
||||
import org.apache.dolphinscheduler.common.thread.Stopper;
|
||||
import org.apache.dolphinscheduler.common.utils.DependentUtils;
|
||||
import org.apache.dolphinscheduler.common.utils.LoggerUtils;
|
||||
import org.apache.dolphinscheduler.common.utils.NetUtils;
|
||||
import org.apache.dolphinscheduler.dao.entity.ProcessInstance;
|
||||
import org.apache.dolphinscheduler.dao.entity.TaskDefinition;
|
||||
import org.apache.dolphinscheduler.dao.entity.TaskInstance;
|
||||
import org.apache.dolphinscheduler.server.master.config.MasterConfig;
|
||||
import org.apache.dolphinscheduler.server.utils.DependentExecute;
|
||||
import org.apache.dolphinscheduler.server.utils.LogUtils;
|
||||
import org.apache.dolphinscheduler.service.bean.SpringApplicationContext;
|
||||
import org.apache.dolphinscheduler.service.process.ProcessService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
@ -38,11 +42,12 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
public class DependentTaskExecThread extends MasterBaseTaskExecThread {
|
||||
/**
|
||||
* dependent task processor
|
||||
*/
|
||||
public class DependentTaskProcessor extends BaseTaskProcessor {
|
||||
|
||||
private DependentParameters dependentParameters;
|
||||
|
||||
@ -57,43 +62,74 @@ public class DependentTaskExecThread extends MasterBaseTaskExecThread {
|
||||
*/
|
||||
private Map<String, DependResult> dependResultMap = new HashMap<>();
|
||||
|
||||
|
||||
/**
|
||||
* dependent date
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date dependentDate;
|
||||
|
||||
/**
|
||||
* constructor of MasterBaseTaskExecThread
|
||||
*
|
||||
* @param taskInstance task instance
|
||||
*/
|
||||
public DependentTaskExecThread(TaskInstance taskInstance) {
|
||||
super(taskInstance);
|
||||
taskInstance.setStartTime(new Date());
|
||||
}
|
||||
DependResult result;
|
||||
|
||||
ProcessInstance processInstance;
|
||||
TaskDefinition taskDefinition;
|
||||
|
||||
protected ProcessService processService = SpringApplicationContext.getBean(ProcessService.class);
|
||||
MasterConfig masterConfig = SpringApplicationContext.getBean(MasterConfig.class);
|
||||
|
||||
boolean allDependentItemFinished;
|
||||
|
||||
@Override
|
||||
public Boolean submitWaitComplete() {
|
||||
try {
|
||||
logger.info("dependent task start");
|
||||
this.taskInstance = submit();
|
||||
logger = LoggerFactory.getLogger(LoggerUtils.buildTaskId(LoggerUtils.TASK_LOGGER_INFO_PREFIX,
|
||||
processInstance.getProcessDefinitionCode(),
|
||||
processInstance.getProcessDefinitionVersion(),
|
||||
taskInstance.getProcessInstanceId(),
|
||||
taskInstance.getId()));
|
||||
String threadLoggerInfoName = String.format(Constants.TASK_LOG_INFO_FORMAT, processService.formatTaskAppId(this.taskInstance));
|
||||
Thread.currentThread().setName(threadLoggerInfoName);
|
||||
initTaskParameters();
|
||||
initDependParameters();
|
||||
waitTaskQuit();
|
||||
updateTaskState();
|
||||
} catch (Exception e) {
|
||||
logger.error("dependent task run exception", e);
|
||||
public boolean submit(TaskInstance task, ProcessInstance processInstance, int masterTaskCommitRetryTimes, int masterTaskCommitInterval) {
|
||||
this.processInstance = processInstance;
|
||||
this.taskInstance = task;
|
||||
this.taskInstance = processService.submitTask(task, masterTaskCommitRetryTimes, masterTaskCommitInterval);
|
||||
|
||||
if (this.taskInstance == null) {
|
||||
return false;
|
||||
}
|
||||
taskDefinition = processService.findTaskDefinition(
|
||||
taskInstance.getTaskCode(), taskInstance.getTaskDefinitionVersion()
|
||||
);
|
||||
taskInstance.setLogPath(LogUtils.getTaskLogPath(processInstance.getProcessDefinitionCode(),
|
||||
processInstance.getProcessDefinitionVersion(),
|
||||
taskInstance.getProcessInstanceId(),
|
||||
taskInstance.getId()));
|
||||
taskInstance.setHost(NetUtils.getAddr(masterConfig.getListenPort()));
|
||||
taskInstance.setState(ExecutionStatus.RUNNING_EXECUTION);
|
||||
taskInstance.setStartTime(new Date());
|
||||
processService.updateTaskInstance(taskInstance);
|
||||
initDependParameters();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExecutionStatus taskState() {
|
||||
return this.taskInstance.getState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!allDependentItemFinished) {
|
||||
allDependentItemFinished = allDependentTaskFinish();
|
||||
}
|
||||
if (allDependentItemFinished) {
|
||||
getTaskDependResult();
|
||||
endTask();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean taskTimeout() {
|
||||
TaskTimeoutStrategy taskTimeoutStrategy =
|
||||
taskDefinition.getTimeoutNotifyStrategy();
|
||||
if (TaskTimeoutStrategy.FAILED != taskTimeoutStrategy
|
||||
&& TaskTimeoutStrategy.WARNFAILED != taskTimeoutStrategy) {
|
||||
return true;
|
||||
}
|
||||
logger.info("dependent task {} timeout, strategy {} ",
|
||||
taskInstance.getId(), taskTimeoutStrategy.getDescp());
|
||||
result = DependResult.FAILED;
|
||||
endTask();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -105,89 +141,27 @@ public class DependentTaskExecThread extends MasterBaseTaskExecThread {
|
||||
for (DependentTaskModel taskModel : dependentParameters.getDependTaskList()) {
|
||||
this.dependentTaskList.add(new DependentExecute(taskModel.getDependItemList(), taskModel.getRelation()));
|
||||
}
|
||||
if (this.processInstance.getScheduleTime() != null) {
|
||||
if (processInstance.getScheduleTime() != null) {
|
||||
this.dependentDate = this.processInstance.getScheduleTime();
|
||||
} else {
|
||||
this.dependentDate = new Date();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private void updateTaskState() {
|
||||
ExecutionStatus status;
|
||||
if (this.cancel) {
|
||||
status = ExecutionStatus.KILL;
|
||||
} else {
|
||||
DependResult result = getTaskDependResult();
|
||||
status = (result == DependResult.SUCCESS) ? ExecutionStatus.SUCCESS : ExecutionStatus.FAILURE;
|
||||
}
|
||||
taskInstance.setState(status);
|
||||
taskInstance.setEndTime(new Date());
|
||||
@Override
|
||||
protected boolean pauseTask() {
|
||||
this.taskInstance.setState(ExecutionStatus.PAUSE);
|
||||
this.taskInstance.setEndTime(new Date());
|
||||
processService.saveTaskInstance(taskInstance);
|
||||
}
|
||||
|
||||
/**
|
||||
* wait dependent tasks quit
|
||||
*/
|
||||
private Boolean waitTaskQuit() {
|
||||
logger.info("wait depend task : {} complete", this.taskInstance.getName());
|
||||
if (taskInstance.getState().typeIsFinished()) {
|
||||
logger.info("task {} already complete. task state:{}",
|
||||
this.taskInstance.getName(),
|
||||
this.taskInstance.getState());
|
||||
return true;
|
||||
}
|
||||
while (Stopper.isRunning()) {
|
||||
try {
|
||||
if (this.processInstance == null) {
|
||||
logger.error("process instance not exists , master task exec thread exit");
|
||||
return true;
|
||||
}
|
||||
if (checkTaskTimeout()) {
|
||||
this.checkTimeoutFlag = !alertTimeout();
|
||||
handleTimeoutFailed();
|
||||
}
|
||||
if (this.cancel || this.processInstance.getState() == ExecutionStatus.READY_STOP) {
|
||||
cancelTaskInstance();
|
||||
break;
|
||||
}
|
||||
|
||||
if (allDependentTaskFinish() || taskInstance.getState().typeIsFinished()) {
|
||||
break;
|
||||
}
|
||||
// update process task
|
||||
taskInstance = processService.findTaskInstanceById(taskInstance.getId());
|
||||
processInstance = processService.findProcessInstanceById(processInstance.getId());
|
||||
Thread.sleep(Constants.SLEEP_TIME_MILLIS);
|
||||
} catch (Exception e) {
|
||||
logger.error("exception", e);
|
||||
if (processInstance != null) {
|
||||
logger.error("wait task quit failed, instance id:{}, task id:{}",
|
||||
processInstance.getId(), taskInstance.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* cancel dependent task
|
||||
*/
|
||||
private void cancelTaskInstance() {
|
||||
this.cancel = true;
|
||||
}
|
||||
|
||||
private void initTaskParameters() {
|
||||
taskInstance.setLogPath(LogUtils.getTaskLogPath(processInstance.getProcessDefinitionCode(),
|
||||
processInstance.getProcessDefinitionVersion(),
|
||||
taskInstance.getProcessInstanceId(),
|
||||
taskInstance.getId()));
|
||||
taskInstance.setHost(NetUtils.getAddr(masterConfig.getListenPort()));
|
||||
taskInstance.setState(ExecutionStatus.RUNNING_EXECUTION);
|
||||
taskInstance.setStartTime(new Date());
|
||||
processService.updateTaskInstance(taskInstance);
|
||||
@Override
|
||||
protected boolean killTask() {
|
||||
this.taskInstance.setState(ExecutionStatus.KILL);
|
||||
this.taskInstance.setEndTime(new Date());
|
||||
processService.saveTaskInstance(taskInstance);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -223,8 +197,24 @@ public class DependentTaskExecThread extends MasterBaseTaskExecThread {
|
||||
DependResult dependResult = dependentExecute.getModelDependResult(dependentDate);
|
||||
dependResultList.add(dependResult);
|
||||
}
|
||||
DependResult result = DependentUtils.getDependResultForRelation(this.dependentParameters.getRelation(), dependResultList);
|
||||
result = DependentUtils.getDependResultForRelation(this.dependentParameters.getRelation(), dependResultList);
|
||||
logger.info("dependent task completed, dependent result:{}", result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private void endTask() {
|
||||
ExecutionStatus status;
|
||||
status = (result == DependResult.SUCCESS) ? ExecutionStatus.SUCCESS : ExecutionStatus.FAILURE;
|
||||
taskInstance.setState(status);
|
||||
taskInstance.setEndTime(new Date());
|
||||
processService.saveTaskInstance(taskInstance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return TaskType.DEPENDENT.getDesc();
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.server.master.runner.task;
|
||||
|
||||
public interface ITaskProcessFactory {
|
||||
|
||||
String type();
|
||||
|
||||
ITaskProcessor create();
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.server.master.runner.task;
|
||||
|
||||
import org.apache.dolphinscheduler.common.enums.ExecutionStatus;
|
||||
import org.apache.dolphinscheduler.dao.entity.ProcessInstance;
|
||||
import org.apache.dolphinscheduler.dao.entity.TaskInstance;
|
||||
|
||||
/**
|
||||
* interface of task processor in master
|
||||
*/
|
||||
public interface ITaskProcessor {
|
||||
|
||||
void run();
|
||||
|
||||
boolean action(TaskAction taskAction);
|
||||
|
||||
String getType();
|
||||
|
||||
boolean submit(TaskInstance taskInstance, ProcessInstance processInstance, int masterTaskCommitRetryTimes, int masterTaskCommitInterval);
|
||||
|
||||
ExecutionStatus taskState();
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.server.master.runner.task;
|
||||
|
||||
import org.apache.dolphinscheduler.common.enums.TaskType;
|
||||
|
||||
public class SubTaskProcessFactory implements ITaskProcessFactory {
|
||||
@Override
|
||||
public String type() {
|
||||
return TaskType.SUB_PROCESS.getDesc();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITaskProcessor create() {
|
||||
return new SubTaskProcessor();
|
||||
}
|
||||
}
|
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.server.master.runner.task;
|
||||
|
||||
import org.apache.dolphinscheduler.common.enums.ExecutionStatus;
|
||||
import org.apache.dolphinscheduler.common.enums.TaskTimeoutStrategy;
|
||||
import org.apache.dolphinscheduler.common.enums.TaskType;
|
||||
import org.apache.dolphinscheduler.dao.entity.ProcessInstance;
|
||||
import org.apache.dolphinscheduler.dao.entity.TaskDefinition;
|
||||
import org.apache.dolphinscheduler.dao.entity.TaskInstance;
|
||||
import org.apache.dolphinscheduler.service.bean.SpringApplicationContext;
|
||||
import org.apache.dolphinscheduler.service.process.ProcessService;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class SubTaskProcessor extends BaseTaskProcessor {
|
||||
|
||||
private ProcessInstance processInstance;
|
||||
|
||||
private ProcessInstance subProcessInstance = null;
|
||||
private TaskDefinition taskDefinition;
|
||||
|
||||
/**
|
||||
* run lock
|
||||
*/
|
||||
private final Lock runLock = new ReentrantLock();
|
||||
|
||||
protected ProcessService processService = SpringApplicationContext.getBean(ProcessService.class);
|
||||
|
||||
@Override
|
||||
public boolean submit(TaskInstance task, ProcessInstance processInstance, int masterTaskCommitRetryTimes, int masterTaskCommitInterval) {
|
||||
this.processInstance = processInstance;
|
||||
taskDefinition = processService.findTaskDefinition(
|
||||
task.getTaskCode(), task.getTaskDefinitionVersion()
|
||||
);
|
||||
this.taskInstance = processService.submitTask(task, masterTaskCommitRetryTimes, masterTaskCommitInterval);
|
||||
|
||||
if (this.taskInstance == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExecutionStatus taskState() {
|
||||
return this.taskInstance.getState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
this.runLock.lock();
|
||||
if (setSubWorkFlow()) {
|
||||
updateTaskState();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("work flow {} sub task {} exceptions",
|
||||
this.processInstance.getId(),
|
||||
this.taskInstance.getId(),
|
||||
e);
|
||||
} finally {
|
||||
this.runLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean taskTimeout() {
|
||||
TaskTimeoutStrategy taskTimeoutStrategy =
|
||||
taskDefinition.getTimeoutNotifyStrategy();
|
||||
if (TaskTimeoutStrategy.FAILED != taskTimeoutStrategy
|
||||
&& TaskTimeoutStrategy.WARNFAILED != taskTimeoutStrategy) {
|
||||
return true;
|
||||
}
|
||||
logger.info("sub process task {} timeout, strategy {} ",
|
||||
taskInstance.getId(), taskTimeoutStrategy.getDescp());
|
||||
killTask();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void updateTaskState() {
|
||||
subProcessInstance = processService.findSubProcessInstance(processInstance.getId(), taskInstance.getId());
|
||||
logger.info("work flow {} task {}, sub work flow: {} state: {}",
|
||||
this.processInstance.getId(),
|
||||
this.taskInstance.getId(),
|
||||
subProcessInstance.getId(),
|
||||
subProcessInstance.getState().getDescp());
|
||||
if (subProcessInstance != null && subProcessInstance.getState().typeIsFinished()) {
|
||||
taskInstance.setState(subProcessInstance.getState());
|
||||
taskInstance.setEndTime(new Date());
|
||||
processService.saveTaskInstance(taskInstance);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean pauseTask() {
|
||||
pauseSubWorkFlow();
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean pauseSubWorkFlow() {
|
||||
ProcessInstance subProcessInstance = processService.findSubProcessInstance(processInstance.getId(), taskInstance.getId());
|
||||
if (subProcessInstance == null || taskInstance.getState().typeIsFinished()) {
|
||||
return false;
|
||||
}
|
||||
subProcessInstance.setState(ExecutionStatus.READY_PAUSE);
|
||||
processService.updateProcessInstance(subProcessInstance);
|
||||
//TODO...
|
||||
// send event to sub process master
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean setSubWorkFlow() {
|
||||
logger.info("set work flow {} task {} running",
|
||||
this.processInstance.getId(),
|
||||
this.taskInstance.getId());
|
||||
if (this.subProcessInstance != null) {
|
||||
return true;
|
||||
}
|
||||
subProcessInstance = processService.findSubProcessInstance(processInstance.getId(), taskInstance.getId());
|
||||
if (subProcessInstance == null || taskInstance.getState().typeIsFinished()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
taskInstance.setState(ExecutionStatus.RUNNING_EXECUTION);
|
||||
taskInstance.setStartTime(new Date());
|
||||
processService.updateTaskInstance(taskInstance);
|
||||
logger.info("set sub work flow {} task {} state: {}",
|
||||
processInstance.getId(),
|
||||
taskInstance.getId(),
|
||||
taskInstance.getState());
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean killTask() {
|
||||
ProcessInstance subProcessInstance = processService.findSubProcessInstance(processInstance.getId(), taskInstance.getId());
|
||||
if (subProcessInstance == null || taskInstance.getState().typeIsFinished()) {
|
||||
return false;
|
||||
}
|
||||
subProcessInstance.setState(ExecutionStatus.READY_STOP);
|
||||
processService.updateProcessInstance(subProcessInstance);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return TaskType.SUB_PROCESS.getDesc();
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.server.master.runner.task;
|
||||
|
||||
import org.apache.dolphinscheduler.common.enums.TaskType;
|
||||
|
||||
public class SwitchTaskProcessFactory implements ITaskProcessFactory {
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return TaskType.SWITCH.getDesc();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITaskProcessor create() {
|
||||
return new SwitchTaskProcessor();
|
||||
}
|
||||
}
|
@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.server.master.runner.task;
|
||||
|
||||
import org.apache.dolphinscheduler.common.enums.DependResult;
|
||||
import org.apache.dolphinscheduler.common.enums.ExecutionStatus;
|
||||
import org.apache.dolphinscheduler.common.enums.TaskType;
|
||||
import org.apache.dolphinscheduler.common.process.Property;
|
||||
import org.apache.dolphinscheduler.common.task.switchtask.SwitchParameters;
|
||||
import org.apache.dolphinscheduler.common.task.switchtask.SwitchResultVo;
|
||||
import org.apache.dolphinscheduler.common.utils.JSONUtils;
|
||||
import org.apache.dolphinscheduler.common.utils.NetUtils;
|
||||
import org.apache.dolphinscheduler.common.utils.StringUtils;
|
||||
import org.apache.dolphinscheduler.dao.entity.ProcessInstance;
|
||||
import org.apache.dolphinscheduler.dao.entity.TaskDefinition;
|
||||
import org.apache.dolphinscheduler.dao.entity.TaskInstance;
|
||||
import org.apache.dolphinscheduler.server.master.config.MasterConfig;
|
||||
import org.apache.dolphinscheduler.server.utils.LogUtils;
|
||||
import org.apache.dolphinscheduler.server.utils.SwitchTaskUtils;
|
||||
import org.apache.dolphinscheduler.service.bean.SpringApplicationContext;
|
||||
import org.apache.dolphinscheduler.service.process.ProcessService;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class SwitchTaskProcessor extends BaseTaskProcessor {
|
||||
|
||||
protected final String rgex = "['\"]*\\$\\{(.*?)\\}['\"]*";
|
||||
|
||||
private TaskInstance taskInstance;
|
||||
|
||||
private ProcessInstance processInstance;
|
||||
TaskDefinition taskDefinition;
|
||||
|
||||
protected ProcessService processService = SpringApplicationContext.getBean(ProcessService.class);
|
||||
MasterConfig masterConfig = SpringApplicationContext.getBean(MasterConfig.class);
|
||||
|
||||
/**
|
||||
* switch result
|
||||
*/
|
||||
private DependResult conditionResult;
|
||||
|
||||
@Override
|
||||
public boolean submit(TaskInstance taskInstance, ProcessInstance processInstance, int masterTaskCommitRetryTimes, int masterTaskCommitInterval) {
|
||||
|
||||
this.processInstance = processInstance;
|
||||
this.taskInstance = processService.submitTask(taskInstance, masterTaskCommitRetryTimes, masterTaskCommitInterval);
|
||||
|
||||
if (this.taskInstance == null) {
|
||||
return false;
|
||||
}
|
||||
taskDefinition = processService.findTaskDefinition(
|
||||
taskInstance.getTaskCode(), taskInstance.getTaskDefinitionVersion()
|
||||
);
|
||||
taskInstance.setLogPath(LogUtils.getTaskLogPath(processInstance.getProcessDefinitionCode(),
|
||||
processInstance.getProcessDefinitionVersion(),
|
||||
taskInstance.getProcessInstanceId(),
|
||||
taskInstance.getId()));
|
||||
taskInstance.setHost(NetUtils.getAddr(masterConfig.getListenPort()));
|
||||
taskInstance.setState(ExecutionStatus.RUNNING_EXECUTION);
|
||||
taskInstance.setStartTime(new Date());
|
||||
processService.updateTaskInstance(taskInstance);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (!this.taskState().typeIsFinished() && setSwitchResult()) {
|
||||
endTaskState();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("update work flow {} switch task {} state error:",
|
||||
this.processInstance.getId(),
|
||||
this.taskInstance.getId(),
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean pauseTask() {
|
||||
this.taskInstance.setState(ExecutionStatus.PAUSE);
|
||||
this.taskInstance.setEndTime(new Date());
|
||||
processService.saveTaskInstance(taskInstance);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean killTask() {
|
||||
this.taskInstance.setState(ExecutionStatus.KILL);
|
||||
this.taskInstance.setEndTime(new Date());
|
||||
processService.saveTaskInstance(taskInstance);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean taskTimeout() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return TaskType.SWITCH.getDesc();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExecutionStatus taskState() {
|
||||
return this.taskInstance.getState();
|
||||
}
|
||||
|
||||
private boolean setSwitchResult() {
|
||||
List<TaskInstance> taskInstances = processService.findValidTaskListByProcessId(
|
||||
taskInstance.getProcessInstanceId()
|
||||
);
|
||||
Map<String, ExecutionStatus> completeTaskList = new HashMap<>();
|
||||
for (TaskInstance task : taskInstances) {
|
||||
completeTaskList.putIfAbsent(task.getName(), task.getState());
|
||||
}
|
||||
SwitchParameters switchParameters = taskInstance.getSwitchDependency();
|
||||
List<SwitchResultVo> switchResultVos = switchParameters.getDependTaskList();
|
||||
SwitchResultVo switchResultVo = new SwitchResultVo();
|
||||
switchResultVo.setNextNode(switchParameters.getNextNode());
|
||||
switchResultVos.add(switchResultVo);
|
||||
int finalConditionLocation = switchResultVos.size() - 1;
|
||||
int i = 0;
|
||||
conditionResult = DependResult.SUCCESS;
|
||||
for (SwitchResultVo info : switchResultVos) {
|
||||
logger.info("the {} execution ", (i + 1));
|
||||
logger.info("original condition sentence:{}", info.getCondition());
|
||||
if (StringUtils.isEmpty(info.getCondition())) {
|
||||
finalConditionLocation = i;
|
||||
break;
|
||||
}
|
||||
String content = setTaskParams(info.getCondition().replaceAll("'", "\""), rgex);
|
||||
logger.info("format condition sentence::{}", content);
|
||||
Boolean result = null;
|
||||
try {
|
||||
result = SwitchTaskUtils.evaluate(content);
|
||||
} catch (Exception e) {
|
||||
logger.info("error sentence : {}", content);
|
||||
conditionResult = DependResult.FAILED;
|
||||
break;
|
||||
}
|
||||
logger.info("condition result : {}", result);
|
||||
if (result) {
|
||||
finalConditionLocation = i;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
switchParameters.setDependTaskList(switchResultVos);
|
||||
switchParameters.setResultConditionLocation(finalConditionLocation);
|
||||
taskInstance.setSwitchDependency(switchParameters);
|
||||
|
||||
logger.info("the switch task depend result : {}", conditionResult);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* update task state
|
||||
*/
|
||||
private void endTaskState() {
|
||||
ExecutionStatus status = (conditionResult == DependResult.SUCCESS) ? ExecutionStatus.SUCCESS : ExecutionStatus.FAILURE;
|
||||
taskInstance.setEndTime(new Date());
|
||||
taskInstance.setState(status);
|
||||
processService.updateTaskInstance(taskInstance);
|
||||
}
|
||||
|
||||
public String setTaskParams(String content, String rgex) {
|
||||
Pattern pattern = Pattern.compile(rgex);
|
||||
Matcher m = pattern.matcher(content);
|
||||
Map<String, Property> globalParams = JSONUtils
|
||||
.toList(processInstance.getGlobalParams(), Property.class)
|
||||
.stream()
|
||||
.collect(Collectors.toMap(Property::getProp, Property -> Property));
|
||||
Map<String, Property> varParams = JSONUtils
|
||||
.toList(taskInstance.getVarPool(), Property.class)
|
||||
.stream()
|
||||
.collect(Collectors.toMap(Property::getProp, Property -> Property));
|
||||
if (varParams.size() > 0) {
|
||||
varParams.putAll(globalParams);
|
||||
globalParams = varParams;
|
||||
}
|
||||
while (m.find()) {
|
||||
String paramName = m.group(1);
|
||||
Property property = globalParams.get(paramName);
|
||||
if (property == null) {
|
||||
return "";
|
||||
}
|
||||
String value = property.getValue();
|
||||
if (!org.apache.commons.lang.math.NumberUtils.isNumber(value)) {
|
||||
value = "\"" + value + "\"";
|
||||
}
|
||||
logger.info("paramName:{},paramValue{}", paramName, value);
|
||||
content = content.replace("${" + paramName + "}", value);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.server.master.runner.task;
|
||||
|
||||
/**
|
||||
* task action
|
||||
*/
|
||||
public enum TaskAction {
|
||||
PAUSE,
|
||||
STOP,
|
||||
TIMEOUT
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.server.master.runner.task;
|
||||
|
||||
import org.apache.dolphinscheduler.common.Constants;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
/**
|
||||
* the factory to create task processor
|
||||
*/
|
||||
public class TaskProcessorFactory {
|
||||
|
||||
public static final Map<String, ITaskProcessFactory> PROCESS_FACTORY_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
private static final String DEFAULT_PROCESSOR = Constants.COMMON_TASK_TYPE;
|
||||
|
||||
static {
|
||||
for (ITaskProcessFactory iTaskProcessor : ServiceLoader.load(ITaskProcessFactory.class)) {
|
||||
PROCESS_FACTORY_MAP.put(iTaskProcessor.type(), iTaskProcessor);
|
||||
}
|
||||
}
|
||||
|
||||
public static ITaskProcessor getTaskProcessor(String type) {
|
||||
if (Strings.isNullOrEmpty(type)) {
|
||||
return PROCESS_FACTORY_MAP.get(DEFAULT_PROCESSOR).create();
|
||||
}
|
||||
if (!PROCESS_FACTORY_MAP.containsKey(type)) {
|
||||
return PROCESS_FACTORY_MAP.get(DEFAULT_PROCESSOR).create();
|
||||
}
|
||||
return PROCESS_FACTORY_MAP.get(type).create();
|
||||
}
|
||||
|
||||
}
|
@ -85,38 +85,41 @@ public class HeartBeatTask implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
double loadAverage = OSUtils.loadAverage();
|
||||
double availablePhysicalMemorySize = OSUtils.availablePhysicalMemorySize();
|
||||
int status = Constants.NORMAL_NODE_STATUS;
|
||||
if (loadAverage > maxCpuloadAvg || availablePhysicalMemorySize < reservedMemory) {
|
||||
logger.warn("current cpu load average {} is too high or available memory {}G is too low, under max.cpuload.avg={} and reserved.memory={}G",
|
||||
loadAverage, availablePhysicalMemorySize, maxCpuloadAvg, reservedMemory);
|
||||
status = Constants.ABNORMAL_NODE_STATUS;
|
||||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder(100);
|
||||
builder.append(OSUtils.cpuUsage()).append(COMMA);
|
||||
builder.append(OSUtils.memoryUsage()).append(COMMA);
|
||||
builder.append(OSUtils.loadAverage()).append(COMMA);
|
||||
builder.append(OSUtils.availablePhysicalMemorySize()).append(Constants.COMMA);
|
||||
builder.append(maxCpuloadAvg).append(Constants.COMMA);
|
||||
builder.append(reservedMemory).append(Constants.COMMA);
|
||||
builder.append(startTime).append(Constants.COMMA);
|
||||
builder.append(DateUtils.dateToString(new Date())).append(Constants.COMMA);
|
||||
builder.append(status).append(COMMA);
|
||||
// save process id
|
||||
builder.append(OSUtils.getProcessID());
|
||||
// worker host weight
|
||||
if (Constants.WORKER_TYPE.equals(serverType)) {
|
||||
builder.append(Constants.COMMA).append(hostWeight);
|
||||
}
|
||||
|
||||
for (String heartBeatPath : heartBeatPaths) {
|
||||
registryClient.update(heartBeatPath, builder.toString());
|
||||
registryClient.update(heartBeatPath, heartBeatInfo());
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
logger.error("error write heartbeat info", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public String heartBeatInfo() {
|
||||
double loadAverage = OSUtils.loadAverage();
|
||||
double availablePhysicalMemorySize = OSUtils.availablePhysicalMemorySize();
|
||||
int status = Constants.NORMAL_NODE_STATUS;
|
||||
if (loadAverage > maxCpuloadAvg || availablePhysicalMemorySize < reservedMemory) {
|
||||
logger.warn("current cpu load average {} is too high or available memory {}G is too low, under max.cpuload.avg={} and reserved.memory={}G",
|
||||
loadAverage, availablePhysicalMemorySize, maxCpuloadAvg, reservedMemory);
|
||||
status = Constants.ABNORMAL_NODE_STATUS;
|
||||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder(100);
|
||||
builder.append(OSUtils.cpuUsage()).append(COMMA);
|
||||
builder.append(OSUtils.memoryUsage()).append(COMMA);
|
||||
builder.append(OSUtils.loadAverage()).append(COMMA);
|
||||
builder.append(OSUtils.availablePhysicalMemorySize()).append(Constants.COMMA);
|
||||
builder.append(maxCpuloadAvg).append(Constants.COMMA);
|
||||
builder.append(reservedMemory).append(Constants.COMMA);
|
||||
builder.append(startTime).append(Constants.COMMA);
|
||||
builder.append(DateUtils.dateToString(new Date())).append(Constants.COMMA);
|
||||
builder.append(status).append(COMMA);
|
||||
// save process id
|
||||
builder.append(OSUtils.getProcessID());
|
||||
// worker host weight
|
||||
if (Constants.WORKER_TYPE.equals(serverType)) {
|
||||
builder.append(Constants.COMMA).append(hostWeight);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.server.utils;
|
||||
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
|
||||
public class SwitchTaskUtils {
|
||||
private static ScriptEngineManager manager;
|
||||
private static ScriptEngine engine;
|
||||
|
||||
static {
|
||||
manager = new ScriptEngineManager();
|
||||
engine = manager.getEngineByName("js");
|
||||
}
|
||||
|
||||
public static boolean evaluate(String expression) throws ScriptException {
|
||||
Object result = engine.eval(expression);
|
||||
return (Boolean) result;
|
||||
}
|
||||
|
||||
}
|
@ -27,6 +27,7 @@ import org.apache.dolphinscheduler.remote.config.NettyServerConfig;
|
||||
import org.apache.dolphinscheduler.server.worker.config.WorkerConfig;
|
||||
import org.apache.dolphinscheduler.server.worker.processor.DBTaskAckProcessor;
|
||||
import org.apache.dolphinscheduler.server.worker.processor.DBTaskResponseProcessor;
|
||||
import org.apache.dolphinscheduler.server.worker.processor.HostUpdateProcessor;
|
||||
import org.apache.dolphinscheduler.server.worker.processor.TaskExecuteProcessor;
|
||||
import org.apache.dolphinscheduler.server.worker.processor.TaskKillProcessor;
|
||||
import org.apache.dolphinscheduler.server.worker.registry.WorkerRegistryClient;
|
||||
@ -124,6 +125,7 @@ public class WorkerServer implements IStoppable {
|
||||
serverConfig.setListenPort(workerConfig.getListenPort());
|
||||
this.nettyRemotingServer = new NettyRemotingServer(serverConfig);
|
||||
this.nettyRemotingServer.registerProcessor(CommandType.TASK_EXECUTE_REQUEST, new TaskExecuteProcessor(alertClientService));
|
||||
this.nettyRemotingServer.registerProcessor(CommandType.PROCESS_HOST_UPDATE_REQUST, new HostUpdateProcessor());
|
||||
this.nettyRemotingServer.registerProcessor(CommandType.TASK_KILL_REQUEST, new TaskKillProcessor());
|
||||
this.nettyRemotingServer.registerProcessor(CommandType.DB_TASK_ACK, new DBTaskAckProcessor());
|
||||
this.nettyRemotingServer.registerProcessor(CommandType.DB_TASK_RESPONSE, new DBTaskResponseProcessor());
|
||||
@ -181,6 +183,7 @@ public class WorkerServer implements IStoppable {
|
||||
this.nettyRemotingServer.close();
|
||||
this.workerRegistryClient.unRegistry();
|
||||
this.alertClientService.close();
|
||||
this.springApplicationContext.close();
|
||||
} catch (Exception e) {
|
||||
logger.error("worker server stop exception ", e);
|
||||
}
|
||||
|
@ -36,7 +36,6 @@ public class DBTaskResponseProcessor implements NettyRequestProcessor {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(DBTaskResponseProcessor.class);
|
||||
|
||||
|
||||
@Override
|
||||
public void process(Channel channel, Command command) {
|
||||
Preconditions.checkArgument(CommandType.DB_TASK_RESPONSE == command.getType(),
|
||||
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dolphinscheduler.server.worker.processor;
|
||||
|
||||
import org.apache.dolphinscheduler.common.utils.JSONUtils;
|
||||
import org.apache.dolphinscheduler.common.utils.Preconditions;
|
||||
import org.apache.dolphinscheduler.remote.command.Command;
|
||||
import org.apache.dolphinscheduler.remote.command.CommandType;
|
||||
import org.apache.dolphinscheduler.remote.command.HostUpdateCommand;
|
||||
import org.apache.dolphinscheduler.remote.processor.NettyRemoteChannel;
|
||||
import org.apache.dolphinscheduler.remote.processor.NettyRequestProcessor;
|
||||
import org.apache.dolphinscheduler.service.bean.SpringApplicationContext;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
|
||||
/**
|
||||
* update process host
|
||||
* this used when master failover
|
||||
*/
|
||||
public class HostUpdateProcessor implements NettyRequestProcessor {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(HostUpdateProcessor.class);
|
||||
|
||||
/**
|
||||
* task callback service
|
||||
*/
|
||||
private final TaskCallbackService taskCallbackService;
|
||||
|
||||
public HostUpdateProcessor() {
|
||||
this.taskCallbackService = SpringApplicationContext.getBean(TaskCallbackService.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(Channel channel, Command command) {
|
||||
Preconditions.checkArgument(CommandType.PROCESS_HOST_UPDATE_REQUST == command.getType(), String.format("invalid command type : %s", command.getType()));
|
||||
HostUpdateCommand updateCommand = JSONUtils.parseObject(command.getBody(), HostUpdateCommand.class);
|
||||
logger.info("received host update command : {}", updateCommand);
|
||||
taskCallbackService.changeRemoteChannel(updateCommand.getTaskInstanceId(), new NettyRemoteChannel(channel, command.getOpaque()));
|
||||
|
||||
}
|
||||
}
|
@ -19,18 +19,15 @@ package org.apache.dolphinscheduler.server.worker.processor;
|
||||
|
||||
import static org.apache.dolphinscheduler.common.Constants.SLEEP_TIME_MILLIS;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.dolphinscheduler.common.thread.Stopper;
|
||||
import org.apache.dolphinscheduler.common.thread.ThreadUtils;
|
||||
import org.apache.dolphinscheduler.common.utils.CollectionUtils;
|
||||
import org.apache.dolphinscheduler.remote.NettyRemotingClient;
|
||||
import org.apache.dolphinscheduler.remote.command.Command;
|
||||
import org.apache.dolphinscheduler.remote.command.CommandType;
|
||||
import org.apache.dolphinscheduler.remote.config.NettyClientConfig;
|
||||
import org.apache.dolphinscheduler.remote.utils.Host;
|
||||
import org.apache.dolphinscheduler.remote.processor.NettyRemoteChannel;
|
||||
import org.apache.dolphinscheduler.service.registry.RegistryClient;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -40,7 +37,6 @@ import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* task callback service
|
||||
*/
|
||||
@ -77,12 +73,22 @@ public class TaskCallbackService {
|
||||
* add callback channel
|
||||
*
|
||||
* @param taskInstanceId taskInstanceId
|
||||
* @param channel channel
|
||||
* @param channel channel
|
||||
*/
|
||||
public void addRemoteChannel(int taskInstanceId, NettyRemoteChannel channel) {
|
||||
REMOTE_CHANNELS.put(taskInstanceId, channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* change remote channel
|
||||
*/
|
||||
public void changeRemoteChannel(int taskInstanceId, NettyRemoteChannel channel) {
|
||||
if (REMOTE_CHANNELS.containsKey(taskInstanceId)) {
|
||||
REMOTE_CHANNELS.remove(taskInstanceId);
|
||||
}
|
||||
REMOTE_CHANNELS.put(taskInstanceId, channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* get callback channel
|
||||
*
|
||||
@ -100,38 +106,8 @@ public class TaskCallbackService {
|
||||
if (newChannel != null) {
|
||||
return getRemoteChannel(newChannel, nettyRemoteChannel.getOpaque(), taskInstanceId);
|
||||
}
|
||||
logger.warn("original master : {} for task : {} is not reachable, random select master",
|
||||
nettyRemoteChannel.getHost(),
|
||||
taskInstanceId);
|
||||
}
|
||||
|
||||
Set<String> masterNodes = null;
|
||||
int ntries = 0;
|
||||
while (Stopper.isRunning()) {
|
||||
masterNodes = registryClient.getMasterNodesDirectly();
|
||||
if (CollectionUtils.isEmpty(masterNodes)) {
|
||||
logger.info("try {} times but not find any master for task : {}.",
|
||||
ntries + 1,
|
||||
taskInstanceId);
|
||||
masterNodes = null;
|
||||
ThreadUtils.sleep(pause(ntries++));
|
||||
continue;
|
||||
}
|
||||
logger.info("try {} times to find {} masters for task : {}.",
|
||||
ntries + 1,
|
||||
masterNodes.size(),
|
||||
taskInstanceId);
|
||||
for (String masterNode : masterNodes) {
|
||||
newChannel = nettyRemotingClient.getChannel(Host.of(masterNode));
|
||||
if (newChannel != null) {
|
||||
return getRemoteChannel(newChannel, taskInstanceId);
|
||||
}
|
||||
}
|
||||
masterNodes = null;
|
||||
ThreadUtils.sleep(pause(ntries++));
|
||||
}
|
||||
|
||||
throw new IllegalStateException(String.format("all available master nodes : %s are not reachable for task: %s", masterNodes, taskInstanceId));
|
||||
return null;
|
||||
}
|
||||
|
||||
public int pause(int ntries) {
|
||||
@ -163,30 +139,35 @@ public class TaskCallbackService {
|
||||
* send ack
|
||||
*
|
||||
* @param taskInstanceId taskInstanceId
|
||||
* @param command command
|
||||
* @param command command
|
||||
*/
|
||||
public void sendAck(int taskInstanceId, Command command) {
|
||||
NettyRemoteChannel nettyRemoteChannel = getRemoteChannel(taskInstanceId);
|
||||
nettyRemoteChannel.writeAndFlush(command);
|
||||
if (nettyRemoteChannel != null) {
|
||||
nettyRemoteChannel.writeAndFlush(command);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* send result
|
||||
*
|
||||
* @param taskInstanceId taskInstanceId
|
||||
* @param command command
|
||||
* @param command command
|
||||
*/
|
||||
public void sendResult(int taskInstanceId, Command command) {
|
||||
NettyRemoteChannel nettyRemoteChannel = getRemoteChannel(taskInstanceId);
|
||||
nettyRemoteChannel.writeAndFlush(command).addListener(new ChannelFutureListener() {
|
||||
if (nettyRemoteChannel != null) {
|
||||
nettyRemoteChannel.writeAndFlush(command).addListener(new ChannelFutureListener() {
|
||||
|
||||
@Override
|
||||
public void operationComplete(ChannelFuture future) throws Exception {
|
||||
if (future.isSuccess()) {
|
||||
remove(taskInstanceId);
|
||||
return;
|
||||
@Override
|
||||
public void operationComplete(ChannelFuture future) throws Exception {
|
||||
if (future.isSuccess()) {
|
||||
remove(taskInstanceId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ import org.apache.dolphinscheduler.remote.command.Command;
|
||||
import org.apache.dolphinscheduler.remote.command.CommandType;
|
||||
import org.apache.dolphinscheduler.remote.command.TaskExecuteAckCommand;
|
||||
import org.apache.dolphinscheduler.remote.command.TaskExecuteRequestCommand;
|
||||
import org.apache.dolphinscheduler.remote.processor.NettyRemoteChannel;
|
||||
import org.apache.dolphinscheduler.remote.processor.NettyRequestProcessor;
|
||||
import org.apache.dolphinscheduler.server.entity.TaskExecutionContext;
|
||||
import org.apache.dolphinscheduler.server.utils.LogUtils;
|
||||
@ -208,6 +209,8 @@ public class TaskExecuteProcessor implements NettyRequestProcessor {
|
||||
ackCommand.setExecutePath(taskExecutionContext.getExecutePath());
|
||||
}
|
||||
taskExecutionContext.setLogPath(ackCommand.getLogPath());
|
||||
ackCommand.setProcessInstanceId(taskExecutionContext.getProcessInstanceId());
|
||||
|
||||
return ackCommand;
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@ import org.apache.dolphinscheduler.remote.command.Command;
|
||||
import org.apache.dolphinscheduler.remote.command.CommandType;
|
||||
import org.apache.dolphinscheduler.remote.command.TaskKillRequestCommand;
|
||||
import org.apache.dolphinscheduler.remote.command.TaskKillResponseCommand;
|
||||
import org.apache.dolphinscheduler.remote.processor.NettyRemoteChannel;
|
||||
import org.apache.dolphinscheduler.remote.processor.NettyRequestProcessor;
|
||||
import org.apache.dolphinscheduler.remote.utils.Host;
|
||||
import org.apache.dolphinscheduler.remote.utils.Pair;
|
||||
|
@ -42,6 +42,7 @@ public class RetryReportTaskStatusThread implements Runnable {
|
||||
* every 5 minutes
|
||||
*/
|
||||
private static long RETRY_REPORT_TASK_STATUS_INTERVAL = 5 * 60 * 1000L;
|
||||
|
||||
/**
|
||||
* task callback service
|
||||
*/
|
||||
@ -49,6 +50,7 @@ public class RetryReportTaskStatusThread implements Runnable {
|
||||
|
||||
public void start(){
|
||||
Thread thread = new Thread(this,"RetryReportTaskStatusThread");
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,10 @@
|
||||
|
||||
package org.apache.dolphinscheduler.server.worker.runner;
|
||||
|
||||
import static java.util.Calendar.DAY_OF_MONTH;
|
||||
|
||||
import org.apache.dolphinscheduler.common.Constants;
|
||||
import org.apache.dolphinscheduler.common.enums.CommandType;
|
||||
import org.apache.dolphinscheduler.common.enums.Event;
|
||||
import org.apache.dolphinscheduler.common.enums.ExecutionStatus;
|
||||
import org.apache.dolphinscheduler.common.enums.TaskType;
|
||||
@ -118,7 +122,7 @@ public class TaskExecuteThread implements Runnable, Delayed {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
TaskExecuteResponseCommand responseCommand = new TaskExecuteResponseCommand(taskExecutionContext.getTaskInstanceId());
|
||||
TaskExecuteResponseCommand responseCommand = new TaskExecuteResponseCommand(taskExecutionContext.getTaskInstanceId(), taskExecutionContext.getProcessInstanceId());
|
||||
try {
|
||||
logger.info("script path : {}", taskExecutionContext.getExecutePath());
|
||||
// check if the OS user exists
|
||||
@ -153,6 +157,7 @@ public class TaskExecuteThread implements Runnable, Delayed {
|
||||
task = TaskManager.newTask(taskExecutionContext, taskLogger, alertClientService);
|
||||
// task init
|
||||
task.init();
|
||||
preBuildBusinessParams();
|
||||
//init varPool
|
||||
task.getParameters().setVarPool(taskExecutionContext.getVarPool());
|
||||
// task handle
|
||||
@ -182,6 +187,23 @@ public class TaskExecuteThread implements Runnable, Delayed {
|
||||
}
|
||||
}
|
||||
|
||||
private void preBuildBusinessParams() {
|
||||
Map<String, Property> paramsMap = new HashMap<>();
|
||||
// replace variable TIME with $[YYYYmmddd...] in shell file when history run job and batch complement job
|
||||
if (taskExecutionContext.getScheduleTime() != null) {
|
||||
Date date = taskExecutionContext.getScheduleTime();
|
||||
if (CommandType.COMPLEMENT_DATA.getCode() == taskExecutionContext.getCmdTypeIfComplement()) {
|
||||
date = DateUtils.add(taskExecutionContext.getScheduleTime(), DAY_OF_MONTH, 1);
|
||||
}
|
||||
String dateTime = DateUtils.format(date, Constants.PARAMETER_FORMAT_TIME);
|
||||
Property p = new Property();
|
||||
p.setValue(dateTime);
|
||||
p.setProp(Constants.PARAMETER_DATETIME);
|
||||
paramsMap.put(Constants.PARAMETER_DATETIME, p);
|
||||
}
|
||||
taskExecutionContext.setParamsMap(paramsMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* when task finish, clear execute path.
|
||||
*/
|
||||
@ -227,7 +249,6 @@ public class TaskExecuteThread implements Runnable, Delayed {
|
||||
return globalParamsMap;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* kill task
|
||||
*/
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user