背景:配置的dolphin任务,使用的是shell,shell里包含了spark-submit 如下截图。
dolphin
shell
介绍完毕,开始说明现象。 有天有人调整了集群的cdp配置,executor-cores max=1
我之前这里写的是2,所以spark任务就报错了 spark-submit报错_cclovezbf的博客-CSDN博客
不多说,后面改下这个配置就好了,spark任务就能运行起来。
但是在这个过程中发现了一个很严重很严重的问题。 这个任务失败了,报错了,但是dolphin显示状态居然是成功!!!!!!!!!!!!!!!!!!!
报错1 列数不对 还有资源不够,还有我里面涉及的接口网络超时,都是我自己故意模拟的的
很明显这里报错了,那么这个dolphin任务就该是失败状态呀。怎么回事??
直接百度!!!
海豚调度任务如何判断任务成功还是失败(源码)?_海豚调度器3.0api访问hive失败_黑眼圈@~@的博客-CSDN博客
其实我都没怎么看这篇文章,但是还是提示我要去看源码。
public CommandExecuteResult run(String execCommand) throws Exception{
CommandExecuteResult result = new CommandExecuteResult();
if (StringUtils.isEmpty(execCommand)) {
return result;
}
//构建工作环境 dolphin 默认的是/tmp/dolphinscheduler/exec/process/588/2877/1284345/1400413
String commandFilePath = buildCommandFilePath();
//把你在dolphin框框填的command 封装好
// create command file if not exists
createCommandFileIfNotExists(execCommand, commandFilePath);
//创建一个process 准备去执行
//build process
buildProcess(commandFilePath);
//打印输出的内容 其实也就是你在dolphin看到的日志
// parse process output
parseProcessOutput(process);
//获取processid
Integer processId = getProcessId(process);
result.setProcessId(processId);
// cache processId
taskExecutionContext.setProcessId(processId);
taskExecutionContextCacheManager.cacheTaskExecutionContext(taskExecutionContext);
// print process id
logger.info("process start, process id is: {}", processId);
// if timeout occurs, exit directly
long remainTime = getRemaintime();
//注意这里啊 这里还假装看了下status 其实这个一直为true。
// waiting for the run to finish
boolean status = process.waitFor(remainTime, TimeUnit.SECONDS);
logger.info("process has exited, execute path:{}, processId:{} ,exitStatusCode:{}",
taskExecutionContext.getExecutePath(),
processId
, result.getExitStatusCode());
// if SHELL task exit //这里一直为true
if (status) {
// set appIds
List<String> appIds = getAppIds(taskExecutionContext.getLogPath());
result.setAppIds(String.join(Constants.COMMA, appIds));
// SHELL task state
result.setExitStatusCode(process.exitValue());
// if yarn task , yarn state is final state
if (process.exitValue() == 0){
result.setExitStatusCode(isSuccessOfYarnState(appIds) ? EXIT_CODE_SUCCESS : EXIT_CODE_FAILURE);
}
} else {
logger.error("process has failure , exitStatusCode : {} , ready to kill ...", result.getExitStatusCode());
ProcessUtils.kill(taskExecutionContext);
result.setExitStatusCode(EXIT_CODE_FAILURE);
}
return result;
}
if (status) { //这里一直为true
// set appIds //获取application_id ,这里也吊的很,他是根据正则:application_ 去在打印输出的日志里 查这个application_id 我怀疑你echo 这个 他估计也要去查
List<String> appIds = getAppIds(taskExecutionContext.getLogPath());
result.setAppIds(String.join(Constants.COMMA, appIds));// SHELL task state
// 这个exitValue比较重要,这个就是看shell最后退出的状态是什么?正常为0 其余都是失败
result.setExitStatusCode(process.exitValue());// if yarn task , yarn state is final state
//这里是说 shell正常退出了,执行成功了,我就去根据application_id去看任务是否失败
if (process.exitValue() == 0){
result.setExitStatusCode(isSuccessOfYarnState(appIds) ? EXIT_CODE_SUCCESS : EXIT_CODE_FAILURE);
}
}
这里我总结下dolphin判断任务的成功和失败。
shell 成功, 去看yarn是否失败, yarn任务成功 dolphin状态显示成功 否则就失败。
shell 失败, 那么dolphin就是失败。
看着很简单,但是这里又涉及到两个知识点。
1.什么情况下shell叫成功呢?
其实上面说的不太对,
shell 成功= shell结束后的 exitCode=0
shell 失败= shell结束后的 exitCode!=0
2.set -e 的作用
简单的来说, 加了set -e 程序在遇到错误的时候就会停止,就是会抛异常。不加的话 程序会一直往下执行。
#set -e
echo 1
ls/chenchi
echo 2
好了介绍完毕,开始复现dolphin出现这个问题的原因。
cc_no_set.sh
#set -e
spark-submit error
cc_with_set.sh
set -e
spark-submit error
cc.sh
echo "success"
with_set_cc.sh | bash /data/DATA_DIR/share/dw_kpi/shell/cc_with_set.sh bash /data/DATA_DIR/share/dw_kpi/shell/cc.sh | 成功 |
no_set_cc.sh | bash /data/DATA_DIR/share/dw_kpi/shell/cc_no_set.sh bash /data/DATA_DIR/share/dw_kpi/shell/cc.sh | 成功 |
with_set.sh | bash /data/DATA_DIR/share/dw_kpi/shell/cc_with_set.sh | 失败 |
no_set.sh | bash /data/DATA_DIR/share/dw_kpi/shell/cc_no_set.sh | 失败 |
可以看到吧 这里为啥 我加了一个 bash cc.sh 就成功了?
因为dolphin 将两条命令 组装为一个shell
bash fail.sh
bash succes.sh
注意这里是没有加 set -e 的,说明程序执行了fail.sh后还是会继续执行succse.sh,这。。。。最后的结果肯定就是success。
真是他妈的一个大坑。 dolphin的任务状态是由什么决定的? 艹