一、介绍
本篇博客将介绍node节点调用命令行执行引擎的具体方法。
我们需要提前了解的是,在YYSchedule中,一个node节点对应着一个引擎。所有引擎的调用方式都是通过命令行进行调用,比方说,有人写了一个计算的程序,想把它整合到YYSchedule中,那么他就必须让该程序可以通过命令行进行调用,例如java程序就得打成jar包,而他所写的程序便成为了YYSchedule所定义的引擎。
我们将引擎放在指定的位置,之后每次收到一个任务task,都会调用命令行去执行引擎。下面我们便会对执行引擎的过程进行说明。
二、执行命令行
我们使用Process来实现java调用命令行操作。实现方式如下:
// run command
Process process = null;
ProcessBuilder pbuilder = new ProcessBuilder(commandList);
if (workingDir != null)
{
pbuilder.directory(workingDir);
}
process = pbuilder.start();
1、在执行完pbuilder.start()后,我们还需要对执行的结果及状态进行判断,当然我们是基于int retCode = process.waitFor();来进行判断的,但因为实际代码进行了很多的扩充及判断,代码量较大,便不在这里进行讲述。
2、在代码中,commandList是一个形式为List<String>的属性,用于存放执行命令。现在我们来介绍如何封装commandList
三、封装commandList
现在我们举个例子,我们想要执行的命令行java -jar E:\tmp\test\test.jar -a "hahaha"
一般情况下,我们可能会认为直接把这段命令行填充进commandList就能进行运行。但实际上,因为还需要考虑执行程序的操作系统问题,所以在这段命令行前面,我们还需要考虑是在linux或者windows,并添加所需要的参数,代码如下,其中的command就是上面我们所举的命令行,使用这个方法便可以将commandList封装好。
public static List<String> getCommandList(String command) {
List<String> commandList = new ArrayList<String>();
String os = System.getProperty("os.name");
if(os.startsWith("Windows")) {
commandList.add("cmd.exe");
commandList.add("/C");
} else {
commandList.add("/bin/sh");
commandList.add("-c");
}
commandList.add(command);
return commandList;
}
而对于command,我们当然不是直接输入String command = java -jar E:\tmp\test\test.jar -a "hahaha" 来进行直接赋值,下面我们将介绍如何封装command,有兴趣的话了解即可。
四、封装command(了解)
实际上YYSchedule中的命令行格式如下:
/bin/sh, -c, java -jar E:\tmp\test\test.jar -a "hahaha" -file E:\tmp\test\1000019010002\2.txt -taskId 1000019010002 -executorId 192.168.2.91:7000
在这其中 java -jar 以及 -a "hahaha" 为引擎人员自定义,因为引擎负责人在写好自己的程序后,必然清楚自己的程序需要什么参数,以及自己的程序的调用方式是java -jar 亦或者 sh等。而-file -taskId 以及-executorId是YYSchedule自动设置的系统所需要的参数。
1、用户自定义参数
ContextParameter.java专门用于存放参数信息,其结构如下:
public int sequenceNum; // required
public java.lang.String opt; // optional
public java.lang.String content; // optional
sequenceNum代表参数顺序,opt以及content组成参数。并且要求执行方式(例如java -jar )的sequenceNum设置成0。
以上面的命令行为例,第一个ContextParameter :sequenceNum=0 ,content = “java -jar”
第二个ContextParameter:sequenceNum=1,opt=“-a” content = “hahaha”
在YYSchedule集成引擎后,便会要求引擎负责人同时将自定义参数设置完毕。
2、自动设置系统所需参数
略
3、获取命令行
获取命令行也就是从task中获取对应的List<ContextParameter>,然后按顺序将ContextParameter中的参数填充到StringBuilder中,最后再将系统所需参数进行填充。调用getCommand方法后,会返回commandList。
/**
* 获取命令行
*
* @param context
* @return commandList
*/
public static List<String> getCommand(Task task,String fileName,String executionDir) {
// prepare execute commands
StringBuilder commandBuilder = new StringBuilder();
List<ContextParameter> contextParameterList = task.getJobParameter().getContextParameterList();
if (contextParameterList != null && contextParameterList.size() != 0) {
// if parameter sequence matters
String[] parameterArray = new String[contextParameterList.size()];
for (ContextParameter parameter : contextParameterList) {
//将执行参数“例如java -jar”区分开
if(parameter.sequenceNum == 0)
{
parameterArray[0] = parameter.getContent();
parameterArray[0] += " " + executionDir;
continue;
}
parameterArray[parameter.sequenceNum] = (StringUtils.isEmpty(parameter.getOpt()) ? "" : parameter.getOpt()) + " ";
if (!StringUtils.isEmpty(parameter.getContent())) {
if (parameter.getContent().indexOf('"') != -1) {
parameterArray[parameter.sequenceNum] = parameterArray[parameter.sequenceNum] + parameter.getContent();
} else {
parameterArray[parameter.sequenceNum] = parameterArray[parameter.sequenceNum] + '"' + parameter.getContent() + '"';
}
}
}
for (String parameterContent : parameterArray) {
commandBuilder.append(parameterContent + " ");
}
}
commandBuilder.append("-file " + fileName + " ");
commandBuilder.append("-taskId " + task.getTaskId() + " ");
commandBuilder.append("-executorId " + task.getExecutorId() + " ");
return getCommandList(commandBuilder.toString().trim());
}