@ -27,6 +27,7 @@ import org.apache.dolphinscheduler.common.thread.ThreadUtils;
import org.apache.dolphinscheduler.common.utils.OSUtils ;
import org.apache.dolphinscheduler.common.utils.OSUtils ;
import org.apache.dolphinscheduler.plugin.task.api.enums.TaskExecutionStatus ;
import org.apache.dolphinscheduler.plugin.task.api.enums.TaskExecutionStatus ;
import org.apache.dolphinscheduler.plugin.task.api.model.TaskResponse ;
import org.apache.dolphinscheduler.plugin.task.api.model.TaskResponse ;
import org.apache.dolphinscheduler.plugin.task.api.parser.TaskOutputParameterParser ;
import org.apache.dolphinscheduler.plugin.task.api.shell.IShellInterceptor ;
import org.apache.dolphinscheduler.plugin.task.api.shell.IShellInterceptor ;
import org.apache.dolphinscheduler.plugin.task.api.shell.IShellInterceptorBuilder ;
import org.apache.dolphinscheduler.plugin.task.api.shell.IShellInterceptorBuilder ;
import org.apache.dolphinscheduler.plugin.task.api.utils.LogUtils ;
import org.apache.dolphinscheduler.plugin.task.api.utils.LogUtils ;
@ -39,31 +40,25 @@ import org.apache.commons.lang3.StringUtils;
import java.io.BufferedReader ;
import java.io.BufferedReader ;
import java.io.InputStreamReader ;
import java.io.InputStreamReader ;
import java.lang.reflect.Field ;
import java.lang.reflect.Field ;
import java.util.List ;
import java.util.HashMap ;
import java.util.Map ;
import java.util.concurrent.ExecutionException ;
import java.util.concurrent.ExecutionException ;
import java.util.concurrent.ExecutorService ;
import java.util.concurrent.ExecutorService ;
import java.util.concurrent.Future ;
import java.util.concurrent.Future ;
import java.util.concurrent.LinkedBlockingQueue ;
import java.util.concurrent.LinkedBlockingQueue ;
import java.util.concurrent.TimeUnit ;
import java.util.concurrent.TimeUnit ;
import java.util.function.Consumer ;
import java.util.function.Consumer ;
import java.util.regex.Matcher ;
import java.util.regex.Pattern ;
import org.slf4j.Logger ;
import lombok.extern.slf4j.Slf4j ;
import io.fabric8.kubernetes.client.dsl.LogWatch ;
import io.fabric8.kubernetes.client.dsl.LogWatch ;
/ * *
/ * *
* abstract command executor
* abstract command executor
* /
* /
@Slf4j
public abstract class AbstractCommandExecutor {
public abstract class AbstractCommandExecutor {
/ * *
protected volatile Map < String , String > taskOutputParams = new HashMap < > ( ) ;
* rules for extracting Var Pool
* /
protected static final Pattern SETVALUE_REGEX = Pattern . compile ( TaskConstants . SETVALUE_REGEX ) ;
protected StringBuilder varPool = new StringBuilder ( ) ;
/ * *
/ * *
* process
* process
* /
* /
@ -74,11 +69,6 @@ public abstract class AbstractCommandExecutor {
* /
* /
protected Consumer < LinkedBlockingQueue < String > > logHandler ;
protected Consumer < LinkedBlockingQueue < String > > logHandler ;
/ * *
* logger
* /
protected Logger logger ;
/ * *
/ * *
* log list
* log list
* /
* /
@ -98,11 +88,9 @@ public abstract class AbstractCommandExecutor {
protected Future < ? > podLogOutputFuture ;
protected Future < ? > podLogOutputFuture ;
public AbstractCommandExecutor ( Consumer < LinkedBlockingQueue < String > > logHandler ,
public AbstractCommandExecutor ( Consumer < LinkedBlockingQueue < String > > logHandler ,
TaskExecutionContext taskRequest ,
TaskExecutionContext taskRequest ) {
Logger logger ) {
this . logHandler = logHandler ;
this . logHandler = logHandler ;
this . taskRequest = taskRequest ;
this . taskRequest = taskRequest ;
this . logger = logger ;
this . logBuffer = new LinkedBlockingQueue < > ( ) ;
this . logBuffer = new LinkedBlockingQueue < > ( ) ;
this . logBuffer . add ( EMPTY_STRING ) ;
this . logBuffer . add ( EMPTY_STRING ) ;
@ -119,7 +107,7 @@ public abstract class AbstractCommandExecutor {
TaskResponse result = new TaskResponse ( ) ;
TaskResponse result = new TaskResponse ( ) ;
int taskInstanceId = taskRequest . getTaskInstanceId ( ) ;
int taskInstanceId = taskRequest . getTaskInstanceId ( ) ;
if ( null = = TaskExecutionContextCacheManager . getByTaskInstanceId ( taskInstanceId ) ) {
if ( null = = TaskExecutionContextCacheManager . getByTaskInstanceId ( taskInstanceId ) ) {
logger . warn (
log . warn (
"Cannot find the taskInstance: {} from TaskExecutionContextCacheManager, the task might already been killed" ,
"Cannot find the taskInstance: {} from TaskExecutionContextCacheManager, the task might already been killed" ,
taskInstanceId ) ;
taskInstanceId ) ;
result . setExitStatusCode ( EXIT_CODE_KILL ) ;
result . setExitStatusCode ( EXIT_CODE_KILL ) ;
@ -180,7 +168,7 @@ public abstract class AbstractCommandExecutor {
return result ;
return result ;
}
}
// print process id
// print process id
logger . info ( "process start, process id is: {}" , processId ) ;
log . info ( "process start, process id is: {}" , processId ) ;
// if timeout occurs, exit directly
// if timeout occurs, exit directly
long remainTime = getRemainTime ( ) ;
long remainTime = getRemainTime ( ) ;
@ -201,7 +189,7 @@ public abstract class AbstractCommandExecutor {
// Wait the task log process finished.
// Wait the task log process finished.
taskOutputFuture . get ( ) ;
taskOutputFuture . get ( ) ;
} catch ( ExecutionException e ) {
} catch ( ExecutionException e ) {
logger . error ( "Handle task log error" , e ) ;
log . error ( "Handle task log error" , e ) ;
}
}
}
}
@ -212,7 +200,7 @@ public abstract class AbstractCommandExecutor {
// delete pod after successful execution and log collection
// delete pod after successful execution and log collection
ProcessUtils . cancelApplication ( taskRequest ) ;
ProcessUtils . cancelApplication ( taskRequest ) ;
} catch ( ExecutionException e ) {
} catch ( ExecutionException e ) {
logger . error ( "Handle pod log error" , e ) ;
log . error ( "Handle pod log error" , e ) ;
}
}
}
}
@ -223,21 +211,21 @@ public abstract class AbstractCommandExecutor {
result . setExitStatusCode ( this . process . exitValue ( ) ) ;
result . setExitStatusCode ( this . process . exitValue ( ) ) ;
} else {
} else {
logger . error ( "process has failure, the task timeout configuration value is:{}, ready to kill ..." ,
log . error ( "process has failure, the task timeout configuration value is:{}, ready to kill ..." ,
taskRequest . getTaskTimeout ( ) ) ;
taskRequest . getTaskTimeout ( ) ) ;
result . setExitStatusCode ( EXIT_CODE_FAILURE ) ;
result . setExitStatusCode ( EXIT_CODE_FAILURE ) ;
cancelApplication ( ) ;
cancelApplication ( ) ;
}
}
int exitCode = this . process . exitValue ( ) ;
int exitCode = this . process . exitValue ( ) ;
String exitLogMessage = EXIT_CODE_KILL = = exitCode ? "process has killed." : "process has exited." ;
String exitLogMessage = EXIT_CODE_KILL = = exitCode ? "process has killed." : "process has exited." ;
logger . info ( "{} execute path:{}, processId:{} ,exitStatusCode:{} ,processWaitForStatus:{} ,processExitValue:{}" ,
log . info ( "{} execute path:{}, processId:{} ,exitStatusCode:{} ,processWaitForStatus:{} ,processExitValue:{}" ,
exitLogMessage , taskRequest . getExecutePath ( ) , processId , result . getExitStatusCode ( ) , status , exitCode ) ;
exitLogMessage , taskRequest . getExecutePath ( ) , processId , result . getExitStatusCode ( ) , status , exitCode ) ;
return result ;
return result ;
}
}
public String getVarPool ( ) {
public Map < String , String > getTaskOutputParams ( ) {
return varPool . toString ( ) ;
return taskOutputParams ;
}
}
public void cancelApplication ( ) throws InterruptedException {
public void cancelApplication ( ) throws InterruptedException {
@ -246,16 +234,12 @@ public abstract class AbstractCommandExecutor {
}
}
// soft kill
// soft kill
logger . info ( "Begin to kill process process, pid is : {}" , taskRequest . getProcessId ( ) ) ;
log . info ( "Begin to kill process process, pid is : {}" , taskRequest . getProcessId ( ) ) ;
process . destroy ( ) ;
process . destroy ( ) ;
if ( ! process . waitFor ( 5 , TimeUnit . SECONDS ) ) {
if ( ! process . waitFor ( 5 , TimeUnit . SECONDS ) ) {
process . destroyForcibly ( ) ;
process . destroyForcibly ( ) ;
}
}
logger . info ( "Success kill task: {}, pid: {}" , taskRequest . getTaskAppId ( ) , taskRequest . getProcessId ( ) ) ;
log . info ( "Success kill task: {}, pid: {}" , taskRequest . getTaskAppId ( ) , taskRequest . getProcessId ( ) ) ;
}
private void printCommand ( List < String > commands ) {
logger . info ( "task run command: {}" , String . join ( " " , commands ) ) ;
}
}
private void collectPodLogIfNeeded ( ) {
private void collectPodLogIfNeeded ( ) {
@ -299,24 +283,22 @@ public abstract class AbstractCommandExecutor {
ExecutorService getOutputLogService = ThreadUtils
ExecutorService getOutputLogService = ThreadUtils
. newSingleDaemonScheduledExecutorService ( "ResolveOutputLog-thread-" + taskRequest . getTaskName ( ) ) ;
. newSingleDaemonScheduledExecutorService ( "ResolveOutputLog-thread-" + taskRequest . getTaskName ( ) ) ;
getOutputLogService . submit ( ( ) - > {
getOutputLogService . submit ( ( ) - > {
TaskOutputParameterParser taskOutputParameterParser = new TaskOutputParameterParser ( ) ;
try ( BufferedReader inReader = new BufferedReader ( new InputStreamReader ( process . getInputStream ( ) ) ) ) {
try ( BufferedReader inReader = new BufferedReader ( new InputStreamReader ( process . getInputStream ( ) ) ) ) {
LogUtils . setTaskInstanceLogFullPathMDC ( taskRequest . getLogPath ( ) ) ;
LogUtils . setTaskInstanceLogFullPathMDC ( taskRequest . getLogPath ( ) ) ;
String line ;
String line ;
while ( ( line = inReader . readLine ( ) ) ! = null ) {
while ( ( line = inReader . readLine ( ) ) ! = null ) {
if ( line . startsWith ( "${setValue(" ) | | line . startsWith ( "#{setValue(" ) ) {
logBuffer . add ( line ) ;
varPool . append ( findVarPool ( line ) ) ;
taskOutputParameterParser . appendParseLog ( line ) ;
varPool . append ( "$VarPool$" ) ;
} else {
logBuffer . add ( line ) ;
}
}
}
processLogOutputIsSuccess = true ;
processLogOutputIsSuccess = true ;
} catch ( Exception e ) {
} catch ( Exception e ) {
logger . error ( "Parse var pool error" , e ) ;
log . error ( "Parse var pool error" , e ) ;
processLogOutputIsSuccess = true ;
processLogOutputIsSuccess = true ;
} finally {
} finally {
LogUtils . removeTaskInstanceLogFullPathMDC ( ) ;
LogUtils . removeTaskInstanceLogFullPathMDC ( ) ;
}
}
taskOutputParams = taskOutputParameterParser . getTaskOutputParams ( ) ;
} ) ;
} ) ;
getOutputLogService . shutdown ( ) ;
getOutputLogService . shutdown ( ) ;
@ -336,7 +318,7 @@ public abstract class AbstractCommandExecutor {
}
}
}
}
} catch ( Exception e ) {
} catch ( Exception e ) {
logger . error ( "Output task log error" , e ) ;
log . error ( "Output task log error" , e ) ;
} finally {
} finally {
LogUtils . removeTaskInstanceLogFullPathMDC ( ) ;
LogUtils . removeTaskInstanceLogFullPathMDC ( ) ;
}
}
@ -344,20 +326,6 @@ public abstract class AbstractCommandExecutor {
parseProcessOutputExecutorService . shutdown ( ) ;
parseProcessOutputExecutorService . shutdown ( ) ;
}
}
/ * *
* find var pool
*
* @param line
* @return
* /
private String findVarPool ( String line ) {
Matcher matcher = SETVALUE_REGEX . matcher ( line ) ;
if ( matcher . find ( ) ) {
return matcher . group ( 1 ) ;
}
return null ;
}
/ * *
/ * *
* get remain time ( s )
* get remain time ( s )
*
*
@ -389,7 +357,7 @@ public abstract class AbstractCommandExecutor {
processId = f . getInt ( process ) ;
processId = f . getInt ( process ) ;
} catch ( Exception e ) {
} catch ( Exception e ) {
logger . error ( "Get task pid failed" , e ) ;
log . error ( "Get task pid failed" , e ) ;
}
}
return processId ;
return processId ;