|
@@ -14,36 +14,44 @@
|
|
|
* See the License for the specific language governing permissions and
|
|
|
* limitations under the License.
|
|
|
*/
|
|
|
+
|
|
|
package org.apache.dolphinscheduler.server.worker.task;
|
|
|
|
|
|
+import static org.apache.dolphinscheduler.common.Constants.EXIT_CODE_FAILURE;
|
|
|
+import static org.apache.dolphinscheduler.common.Constants.EXIT_CODE_KILL;
|
|
|
+import static org.apache.dolphinscheduler.common.Constants.EXIT_CODE_SUCCESS;
|
|
|
+
|
|
|
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.thread.ThreadUtils;
|
|
|
import org.apache.dolphinscheduler.common.utils.HadoopUtils;
|
|
|
-import org.apache.dolphinscheduler.common.utils.StringUtils;
|
|
|
-import org.apache.dolphinscheduler.dao.entity.TaskInstance;
|
|
|
import org.apache.dolphinscheduler.common.utils.LoggerUtils;
|
|
|
+import org.apache.dolphinscheduler.common.utils.StringUtils;
|
|
|
import org.apache.dolphinscheduler.server.entity.TaskExecutionContext;
|
|
|
import org.apache.dolphinscheduler.server.utils.ProcessUtils;
|
|
|
import org.apache.dolphinscheduler.server.worker.cache.TaskExecutionContextCacheManager;
|
|
|
import org.apache.dolphinscheduler.server.worker.cache.impl.TaskExecutionContextCacheManagerImpl;
|
|
|
import org.apache.dolphinscheduler.service.bean.SpringApplicationContext;
|
|
|
-import org.apache.dolphinscheduler.service.process.ProcessService;
|
|
|
-import org.slf4j.Logger;
|
|
|
|
|
|
-import java.io.*;
|
|
|
+import java.io.BufferedReader;
|
|
|
+import java.io.File;
|
|
|
+import java.io.FileInputStream;
|
|
|
+import java.io.IOException;
|
|
|
+import java.io.InputStreamReader;
|
|
|
import java.lang.reflect.Field;
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
-import java.util.*;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Collections;
|
|
|
+import java.util.LinkedList;
|
|
|
+import java.util.List;
|
|
|
import java.util.concurrent.ExecutorService;
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
import java.util.function.Consumer;
|
|
|
import java.util.regex.Matcher;
|
|
|
import java.util.regex.Pattern;
|
|
|
|
|
|
-import static org.apache.dolphinscheduler.common.Constants.EXIT_CODE_FAILURE;
|
|
|
-import static org.apache.dolphinscheduler.common.Constants.EXIT_CODE_SUCCESS;
|
|
|
+import org.slf4j.Logger;
|
|
|
|
|
|
|
|
|
* abstract command executor
|
|
@@ -56,22 +64,22 @@ public abstract class AbstractCommandExecutor {
|
|
|
|
|
|
protected StringBuilder varPool = new StringBuilder();
|
|
|
|
|
|
- * process
|
|
|
+ * process
|
|
|
*/
|
|
|
private Process process;
|
|
|
|
|
|
|
|
|
- * log handler
|
|
|
+ * log handler
|
|
|
*/
|
|
|
protected Consumer<List<String>> logHandler;
|
|
|
|
|
|
|
|
|
- * logger
|
|
|
+ * logger
|
|
|
*/
|
|
|
protected Logger logger;
|
|
|
|
|
|
|
|
|
- * log list
|
|
|
+ * log list
|
|
|
*/
|
|
|
protected final List<String> logBuffer;
|
|
|
|
|
@@ -86,8 +94,8 @@ public abstract class AbstractCommandExecutor {
|
|
|
private TaskExecutionContextCacheManager taskExecutionContextCacheManager;
|
|
|
|
|
|
public AbstractCommandExecutor(Consumer<List<String>> logHandler,
|
|
|
- TaskExecutionContext taskExecutionContext ,
|
|
|
- Logger logger){
|
|
|
+ TaskExecutionContext taskExecutionContext,
|
|
|
+ Logger logger) {
|
|
|
this.logHandler = logHandler;
|
|
|
this.taskExecutionContext = taskExecutionContext;
|
|
|
this.logger = logger;
|
|
@@ -135,12 +143,18 @@ public abstract class AbstractCommandExecutor {
|
|
|
* @return CommandExecuteResult
|
|
|
* @throws Exception if error throws Exception
|
|
|
*/
|
|
|
- public CommandExecuteResult run(String execCommand) throws Exception{
|
|
|
+ public CommandExecuteResult run(String execCommand) throws Exception {
|
|
|
|
|
|
CommandExecuteResult result = new CommandExecuteResult();
|
|
|
|
|
|
-
|
|
|
+ int taskInstanceId = taskExecutionContext.getTaskInstanceId();
|
|
|
+
|
|
|
+ if (null == taskExecutionContextCacheManager.getByTaskInstanceId(taskInstanceId)) {
|
|
|
+ result.setExitStatusCode(EXIT_CODE_KILL);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
if (StringUtils.isEmpty(execCommand)) {
|
|
|
+ taskExecutionContextCacheManager.removeByTaskInstanceId(taskInstanceId);
|
|
|
return result;
|
|
|
}
|
|
|
|
|
@@ -155,14 +169,18 @@ public abstract class AbstractCommandExecutor {
|
|
|
|
|
|
parseProcessOutput(process);
|
|
|
|
|
|
-
|
|
|
Integer processId = getProcessId(process);
|
|
|
|
|
|
result.setProcessId(processId);
|
|
|
|
|
|
|
|
|
taskExecutionContext.setProcessId(processId);
|
|
|
- taskExecutionContextCacheManager.cacheTaskExecutionContext(taskExecutionContext);
|
|
|
+ boolean updateTaskExecutionContextStatus = taskExecutionContextCacheManager.updateTaskExecutionContext(taskExecutionContext);
|
|
|
+ if (Boolean.FALSE.equals(updateTaskExecutionContextStatus)) {
|
|
|
+ ProcessUtils.kill(taskExecutionContext);
|
|
|
+ result.setExitStatusCode(EXIT_CODE_KILL);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
|
|
|
|
|
|
logger.info("process start, process id is: {}", processId);
|
|
@@ -173,11 +191,10 @@ public abstract class AbstractCommandExecutor {
|
|
|
|
|
|
boolean status = process.waitFor(remainTime, TimeUnit.SECONDS);
|
|
|
|
|
|
-
|
|
|
logger.info("process has exited, execute path:{}, processId:{} ,exitStatusCode:{}",
|
|
|
- taskExecutionContext.getExecutePath(),
|
|
|
- processId
|
|
|
- , result.getExitStatusCode());
|
|
|
+ taskExecutionContext.getExecutePath(),
|
|
|
+ processId
|
|
|
+ , result.getExitStatusCode());
|
|
|
|
|
|
|
|
|
if (status) {
|
|
@@ -189,7 +206,7 @@ public abstract class AbstractCommandExecutor {
|
|
|
result.setExitStatusCode(process.exitValue());
|
|
|
|
|
|
|
|
|
- if (process.exitValue() == 0){
|
|
|
+ if (process.exitValue() == 0) {
|
|
|
result.setExitStatusCode(isSuccessOfYarnState(appIds) ? EXIT_CODE_SUCCESS : EXIT_CODE_FAILURE);
|
|
|
}
|
|
|
} else {
|
|
@@ -198,7 +215,6 @@ public abstract class AbstractCommandExecutor {
|
|
|
result.setExitStatusCode(EXIT_CODE_FAILURE);
|
|
|
}
|
|
|
|
|
|
-
|
|
|
return result;
|
|
|
}
|
|
|
|
|
@@ -208,6 +224,7 @@ public abstract class AbstractCommandExecutor {
|
|
|
|
|
|
|
|
|
* cancel application
|
|
|
+ *
|
|
|
* @throws Exception exception
|
|
|
*/
|
|
|
public void cancelApplication() throws Exception {
|
|
@@ -238,6 +255,7 @@ public abstract class AbstractCommandExecutor {
|
|
|
|
|
|
|
|
|
* soft kill
|
|
|
+ *
|
|
|
* @param processId process id
|
|
|
* @return process is alive
|
|
|
* @throws InterruptedException interrupted exception
|
|
@@ -262,6 +280,7 @@ public abstract class AbstractCommandExecutor {
|
|
|
|
|
|
|
|
|
* hard kill
|
|
|
+ *
|
|
|
* @param processId process id
|
|
|
*/
|
|
|
private void hardKill(int processId) {
|
|
@@ -280,6 +299,7 @@ public abstract class AbstractCommandExecutor {
|
|
|
|
|
|
|
|
|
* print command
|
|
|
+ *
|
|
|
* @param commands process builder
|
|
|
*/
|
|
|
private void printCommand(List<String> commands) {
|
|
@@ -311,12 +331,13 @@ public abstract class AbstractCommandExecutor {
|
|
|
|
|
|
|
|
|
* get the standard output of the process
|
|
|
+ *
|
|
|
* @param process process
|
|
|
*/
|
|
|
private void parseProcessOutput(Process process) {
|
|
|
String threadLoggerInfoName = String.format(LoggerUtils.TASK_LOGGER_THREAD_NAME + "-%s", taskExecutionContext.getTaskAppId());
|
|
|
ExecutorService parseProcessOutputExecutorService = ThreadUtils.newDaemonSingleThreadExecutor(threadLoggerInfoName);
|
|
|
- parseProcessOutputExecutorService.submit(new Runnable(){
|
|
|
+ parseProcessOutputExecutorService.submit(new Runnable() {
|
|
|
@Override
|
|
|
public void run() {
|
|
|
BufferedReader inReader = null;
|
|
@@ -337,7 +358,7 @@ public abstract class AbstractCommandExecutor {
|
|
|
}
|
|
|
}
|
|
|
} catch (Exception e) {
|
|
|
- logger.error(e.getMessage(),e);
|
|
|
+ logger.error(e.getMessage(), e);
|
|
|
} finally {
|
|
|
clear();
|
|
|
close(inReader);
|
|
@@ -357,22 +378,22 @@ public abstract class AbstractCommandExecutor {
|
|
|
boolean result = true;
|
|
|
try {
|
|
|
for (String appId : appIds) {
|
|
|
- while(Stopper.isRunning()){
|
|
|
+ while (Stopper.isRunning()) {
|
|
|
ExecutionStatus applicationStatus = HadoopUtils.getInstance().getApplicationStatus(appId);
|
|
|
- logger.info("appId:{}, final state:{}",appId,applicationStatus.name());
|
|
|
- if (applicationStatus.equals(ExecutionStatus.FAILURE) ||
|
|
|
- applicationStatus.equals(ExecutionStatus.KILL)) {
|
|
|
+ logger.info("appId:{}, final state:{}", appId, applicationStatus.name());
|
|
|
+ if (applicationStatus.equals(ExecutionStatus.FAILURE)
|
|
|
+ || applicationStatus.equals(ExecutionStatus.KILL)) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- if (applicationStatus.equals(ExecutionStatus.SUCCESS)){
|
|
|
+ if (applicationStatus.equals(ExecutionStatus.SUCCESS)) {
|
|
|
break;
|
|
|
}
|
|
|
Thread.sleep(Constants.SLEEP_TIME_MILLIS);
|
|
|
}
|
|
|
}
|
|
|
} catch (Exception e) {
|
|
|
- logger.error(String.format("yarn applications: %s status failed ", appIds.toString()),e);
|
|
|
+ logger.error(String.format("yarn applications: %s status failed ", appIds.toString()), e);
|
|
|
result = false;
|
|
|
}
|
|
|
return result;
|
|
@@ -408,14 +429,15 @@ public abstract class AbstractCommandExecutor {
|
|
|
|
|
|
|
|
|
* convert file to list
|
|
|
+ *
|
|
|
* @param filename file name
|
|
|
* @return line list
|
|
|
*/
|
|
|
private List<String> convertFile2List(String filename) {
|
|
|
List lineList = new ArrayList<String>(100);
|
|
|
- File file=new File(filename);
|
|
|
+ File file = new File(filename);
|
|
|
|
|
|
- if (!file.exists()){
|
|
|
+ if (!file.exists()) {
|
|
|
return lineList;
|
|
|
}
|
|
|
|
|
@@ -427,13 +449,13 @@ public abstract class AbstractCommandExecutor {
|
|
|
lineList.add(line);
|
|
|
}
|
|
|
} catch (Exception e) {
|
|
|
- logger.error(String.format("read file: %s failed : ",filename),e);
|
|
|
+ logger.error(String.format("read file: %s failed : ", filename), e);
|
|
|
} finally {
|
|
|
- if(br != null){
|
|
|
+ if (br != null) {
|
|
|
try {
|
|
|
br.close();
|
|
|
} catch (IOException e) {
|
|
|
- logger.error(e.getMessage(),e);
|
|
|
+ logger.error(e.getMessage(), e);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -443,6 +465,7 @@ public abstract class AbstractCommandExecutor {
|
|
|
|
|
|
|
|
|
* find app id
|
|
|
+ *
|
|
|
* @param line line
|
|
|
* @return appid
|
|
|
*/
|
|
@@ -454,7 +477,6 @@ public abstract class AbstractCommandExecutor {
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
|
|
|
* get remain time(s)
|
|
|
*
|
|
@@ -495,7 +517,7 @@ public abstract class AbstractCommandExecutor {
|
|
|
|
|
|
* when log buffer siz or flush time reach condition , then flush
|
|
|
*
|
|
|
- * @param lastFlushTime last flush time
|
|
|
+ * @param lastFlushTime last flush time
|
|
|
* @return last flush time
|
|
|
*/
|
|
|
private long flush(long lastFlushTime) {
|
|
@@ -532,7 +554,10 @@ public abstract class AbstractCommandExecutor {
|
|
|
protected List<String> commandOptions() {
|
|
|
return Collections.emptyList();
|
|
|
}
|
|
|
+
|
|
|
protected abstract String buildCommandFilePath();
|
|
|
+
|
|
|
protected abstract String commandInterpreter();
|
|
|
+
|
|
|
protected abstract void createCommandFileIfNotExists(String execCommand, String commandFile) throws IOException;
|
|
|
}
|