Просмотр исходного кода

脚本任务实现:Shell和Python

xueli.xue 8 лет назад
Родитель
Сommit
935cc1276f

+ 7 - 9
xxl-job-admin/src/main/webapp/WEB-INF/template/jobinfo/jobinfo.index.ftl Просмотреть файл

@@ -193,17 +193,15 @@ public class DemoGlueJobHandler extends IJobHandler {
193 193
 <textarea class="glueSource_shell" style="display:none;" >
194 194
 #!/bin/bash
195 195
 
196
-echo hello shell
196
+echo "xxl-job: hello shell"
197 197
 
198
-for x in 1 2 3 4
198
+for item in 1 2 3
199 199
 do
200
-echo number=$x
200
+echo "shell : $item"
201 201
 sleep 1s
202 202
 done
203 203
 
204
-echo1 111
205
-printf 666
206
-echo2 222
204
+echo "Good bye!"
207 205
 </textarea>
208 206
 <textarea class="glueSource_python" style="display:none;" >
209 207
 #!/usr/bin/python
@@ -214,11 +212,11 @@ import time
214 212
 
215 213
 logging.basicConfig(level=logging.DEBUG)
216 214
 
217
-logging.info('hello python')
215
+logging.info('xxl-job: hello python')
218 216
 
219
-for num in range(0, 3):
217
+for num in range(1, 3):
220 218
 	time.sleep(1)
221
-	logging.info('当前序号 :' + str(num) )
219
+	logging.info('python :' + str(num) )
222 220
 
223 221
 logging.info('Good bye!')
224 222
 </textarea>

+ 19 - 58
xxl-job-core/src/main/java/com/xxl/job/core/biz/impl/ExecutorBizImpl.java Просмотреть файл

@@ -9,15 +9,12 @@ import com.xxl.job.core.glue.GlueFactory;
9 9
 import com.xxl.job.core.glue.GlueTypeEnum;
10 10
 import com.xxl.job.core.handler.IJobHandler;
11 11
 import com.xxl.job.core.handler.impl.GlueJobHandler;
12
+import com.xxl.job.core.handler.impl.ScriptJobHandler;
12 13
 import com.xxl.job.core.log.XxlJobFileAppender;
13 14
 import com.xxl.job.core.thread.JobThread;
14
-import com.xxl.job.core.util.ScriptUtil;
15 15
 import org.slf4j.Logger;
16 16
 import org.slf4j.LoggerFactory;
17 17
 
18
-import java.io.File;
19
-import java.io.FileOutputStream;
20
-import java.io.IOException;
21 18
 import java.util.Date;
22 19
 
23 20
 /**
@@ -85,11 +82,11 @@ public class ExecutorBizImpl implements ExecutorBiz {
85 82
 
86 83
         } else if (GlueTypeEnum.GLUE_GROOVY==GlueTypeEnum.match(triggerParam.getGlueType())) {
87 84
 
88
-            // valid exists job thread:change handler or glue timeout, need kill old thread
85
+            // valid exists job thread:change handler or gluesource updated, need kill old thread
89 86
             if (jobThread != null &&
90 87
                     !(jobThread.getHandler() instanceof GlueJobHandler
91 88
                         && ((GlueJobHandler) jobThread.getHandler()).getGlueUpdatetime()==triggerParam.getGlueUpdatetime() )) {
92
-                // change glue model or glue timeout, kill old job thread
89
+                // change glue model or gluesource updated, kill old job thread
93 90
                 jobThread.toStop("更换任务模式或JobHandler,终止旧任务线程");
94 91
                 jobThread.interrupt();
95 92
                 XxlJobExecutor.removeJobThread(triggerParam.getJobId());
@@ -107,61 +104,25 @@ public class ExecutorBizImpl implements ExecutorBiz {
107 104
                 }
108 105
                 jobThread = XxlJobExecutor.registJobThread(triggerParam.getJobId(), new GlueJobHandler(jobHandler, triggerParam.getGlueUpdatetime()));
109 106
             }
110
-        } else if (GlueTypeEnum.GLUE_SHELL==GlueTypeEnum.match(triggerParam.getGlueType())) {
111
-
112
-            // make path
113
-            String scriptPath = XxlJobFileAppender.filePath + "gluesource/";
114
-            String scriptFileName = triggerParam.getJobId() + "_" + triggerParam.getGlueUpdatetime() + ".sh";
115
-
116
-            // valid file
117
-            File scriptFile = new File(scriptPath, scriptFileName);
118
-            if (!scriptFile.exists()) {
119
-                // valid glue source
120
-                if (triggerParam.getGlueSource()==null) {
121
-                    return new ReturnT<String>(ReturnT.FAIL_CODE, "glueSource is null.");
122
-                }
123
-
124
-                // .../gluesource/
125
-                File scriptPathDir = new File(scriptPath);
126
-                if (!scriptPathDir.exists()) {
127
-                    scriptPathDir.mkdirs();
128
-                }
129
-
130
-                // .../gluesource/666-156465656.sh
131
-                scriptFile = new File(scriptPath, scriptFileName);
132
-                FileOutputStream fos = null;
133
-                try {
134
-                    scriptFile.createNewFile();
135
-
136
-                    fos = new FileOutputStream(scriptFile, true);
137
-                    fos.write(triggerParam.getGlueSource().getBytes("utf-8"));
138
-                    fos.flush();
139
-                } catch (IOException e) {
140
-                    logger.error(e.getMessage(), e);
141
-                    return new ReturnT<String>(ReturnT.FAIL_CODE, e.getMessage());
142
-                } finally {
143
-                    if (fos != null) {
144
-                        try {
145
-                            fos.close();
146
-                        } catch (IOException e) {
147
-                            logger.error(e.getMessage(), e);
148
-                        }
149
-                    }
150
-                }
107
+        } else if (GlueTypeEnum.GLUE_SHELL==GlueTypeEnum.match(triggerParam.getGlueType())
108
+                || GlueTypeEnum.GLUE_PYTHON==GlueTypeEnum.match(triggerParam.getGlueType()) ) {
151 109
 
110
+            // valid exists job thread:change script or gluesource updated, need kill old thread
111
+            if (jobThread != null &&
112
+                    !(jobThread.getHandler() instanceof ScriptJobHandler
113
+                            && ((ScriptJobHandler) jobThread.getHandler()).getGlueUpdatetime()==triggerParam.getGlueUpdatetime() )) {
114
+                // change glue model or gluesource updated, kill old job thread
115
+                jobThread.toStop("更换任务模式或JobHandler,终止旧任务线程");
116
+                jobThread.interrupt();
117
+                XxlJobExecutor.removeJobThread(triggerParam.getJobId());
118
+                jobThread = null;
152 119
             }
153 120
 
154
-            // log File
155
-            String logFileName = XxlJobFileAppender.makeLogFileName(new Date(triggerParam.getLogDateTim()), triggerParam.getLogId());
156
-
157
-            // run script
158
-            ScriptUtil.execToFile("python", scriptFile.getName(), (XxlJobFileAppender.filePath + logFileName) );
159
-
160
-            return ReturnT.FAIL;
161
-        } else if (GlueTypeEnum.GLUE_PYTHON==GlueTypeEnum.match(triggerParam.getGlueType())) {
162
-            String scriptFilePath = XxlJobFileAppender.filePath + "gluesource/" + triggerParam.getJobId() + "_" + triggerParam.getGlueUpdatetime() + ".py";
163
-
164
-
121
+            // make thread: new or exists invalid
122
+            if (jobThread == null) {
123
+                ScriptJobHandler scriptJobHandler = new ScriptJobHandler(triggerParam.getJobId(), triggerParam.getGlueUpdatetime(), triggerParam.getGlueSource(), GlueTypeEnum.match(triggerParam.getGlueType()));
124
+                jobThread = XxlJobExecutor.registJobThread(triggerParam.getJobId(), scriptJobHandler);
125
+            }
165 126
         } else {
166 127
             return new ReturnT<String>(ReturnT.FAIL_CODE, "glueType[" + triggerParam.getGlueType() + "] is not valid.");
167 128
         }

+ 55 - 0
xxl-job-core/src/main/java/com/xxl/job/core/handler/impl/ScriptJobHandler.java Просмотреть файл

@@ -0,0 +1,55 @@
1
+package com.xxl.job.core.handler.impl;
2
+
3
+import com.xxl.job.core.biz.model.ReturnT;
4
+import com.xxl.job.core.glue.GlueTypeEnum;
5
+import com.xxl.job.core.handler.IJobHandler;
6
+import com.xxl.job.core.log.XxlJobFileAppender;
7
+import com.xxl.job.core.util.ScriptUtil;
8
+
9
+/**
10
+ * Created by xuxueli on 17/4/27.
11
+ */
12
+public class ScriptJobHandler extends IJobHandler {
13
+
14
+    private int jobId;
15
+    private long glueUpdatetime;
16
+    private String gluesource;
17
+    private GlueTypeEnum glueType;
18
+
19
+    public ScriptJobHandler(int jobId, long glueUpdatetime, String gluesource, GlueTypeEnum glueType){
20
+        this.jobId = jobId;
21
+        this.glueUpdatetime = glueUpdatetime;
22
+        this.gluesource = gluesource;
23
+        this.glueType = glueType;
24
+    }
25
+
26
+    public long getGlueUpdatetime() {
27
+        return glueUpdatetime;
28
+    }
29
+
30
+    @Override
31
+    public ReturnT<String> execute(String... params) throws Exception {
32
+
33
+        // cmd + script-file-name
34
+        String cmd = "bash";
35
+        String scriptFileName = null;
36
+        if (GlueTypeEnum.GLUE_SHELL == glueType) {
37
+            cmd = "bash";
38
+            scriptFileName = XxlJobFileAppender.filePath.concat("gluesource/").concat(String.valueOf(jobId)).concat("_").concat(String.valueOf(glueUpdatetime)).concat(".sh");
39
+        } else if (GlueTypeEnum.GLUE_PYTHON == glueType) {
40
+            cmd = "python";
41
+            scriptFileName = XxlJobFileAppender.filePath.concat("gluesource/").concat(String.valueOf(jobId)).concat("_").concat(String.valueOf(glueUpdatetime)).concat(".py");
42
+        }
43
+
44
+        // make script file
45
+        ScriptUtil.markScriptFile(scriptFileName, gluesource);
46
+
47
+        // log file
48
+        String logFileName = XxlJobFileAppender.filePath.concat(XxlJobFileAppender.contextHolder.get());
49
+
50
+        // invoke
51
+        ScriptUtil.execToFile(cmd, scriptFileName, logFileName);
52
+        return ReturnT.SUCCESS;
53
+    }
54
+
55
+}

+ 47 - 46
xxl-job-core/src/main/java/com/xxl/job/core/util/ScriptUtil.java Просмотреть файл

@@ -1,49 +1,57 @@
1 1
 package com.xxl.job.core.util;
2 2
 
3
+import com.xxl.job.core.log.XxlJobFileAppender;
3 4
 import org.apache.commons.exec.CommandLine;
4 5
 import org.apache.commons.exec.DefaultExecutor;
5 6
 import org.apache.commons.exec.PumpStreamHandler;
6 7
 
7 8
 import java.io.File;
8 9
 import java.io.FileOutputStream;
10
+import java.io.IOException;
9 11
 
10 12
 /**
11 13
  *  1、内嵌编译器如"PythonInterpreter"无法引用扩展包,因此推荐使用java调用控制台进程方式"Runtime.getRuntime().exec()"来运行脚本(shell或python);
12 14
  *  2、因为通过java调用控制台进程方式实现,需要保证目标机器PATH路径正确配置对应编译器;
13 15
  *  3、暂时脚本执行日志只能在脚本执行结束后一次性获取,无法保证实时性;因此为确保日志实时性,可改为将脚本打印的日志存储在指定的日志文件上;
14
- *
15
- *  知识点:
16
- *      1、日志输出到日志文件:[>>logfile 2>&1]:将错误输出2以及标准输出1都一起以附加写方式导入logfile文件
17
- *      2、python 异常输出优先级高于标准输出,体现在Log文件中,因此推荐通过logging方式打日志保持和异常信息一致;否则用prinf日志顺序会错乱
16
+ *  4、python 异常输出优先级高于标准输出,体现在Log文件中,因此推荐通过logging方式打日志保持和异常信息一致;否则用prinf日志顺序会错乱
18 17
  *
19 18
  * Created by xuxueli on 17/2/25.
20 19
  */
21 20
 public class ScriptUtil {
22 21
 
23
-    private static String pyCmd = "python";
24
-    private static String shllCmd = "bash";
25
-    private static String pyFile = "/Users/xuxueli/workspaces/idea-git-workspace/github/xxl-incubator/xxl-util/src/main/resources/script/pytest.py";
26
-    private static String shellFile = "/Users/xuxueli/workspaces/idea-git-workspace/github/xxl-incubator/xxl-util/src/main/resources/script/shelltest.sh";
27
-    private static String pyLogFile = "/Users/xuxueli/Downloads/tmp/pylog.log";
28
-    private static String shLogFile = "/Users/xuxueli/Downloads/tmp/shlog.log";
29
-
30
-    public static void main(String[] args) {
31
-
32
-        String command = pyCmd;
33
-        String filename = pyFile;
34
-        String logFile = pyLogFile;
35
-        if (false) {
36
-            command = shllCmd;
37
-            filename = shellFile;
38
-            logFile = shLogFile;
22
+    /**
23
+     * make script file
24
+     *
25
+     * @param scriptFileName
26
+     * @param content
27
+     * @throws IOException
28
+     */
29
+    public static void markScriptFile(String scriptFileName, String content) throws IOException {
30
+        // filePath/
31
+        File filePathDir = new File(XxlJobFileAppender.filePath);
32
+        if (!filePathDir.exists()) {
33
+            filePathDir.mkdirs();
39 34
         }
40 35
 
41
-        execToFile(command, filename, logFile);
42
-
43
-    }
36
+        // filePath/gluesource/
37
+        File filePathSourceDir = new File(filePathDir, "gluesource");
38
+        if (!filePathSourceDir.exists()) {
39
+            filePathSourceDir.mkdirs();
40
+        }
44 41
 
45
-    public static File markScriptFile(){
46
-        return null;
42
+        // make file,   filePath/gluesource/666-123456789.py
43
+        FileOutputStream fileOutputStream = null;
44
+        try {
45
+            fileOutputStream = new FileOutputStream(scriptFileName);
46
+            fileOutputStream.write(content.getBytes("UTF-8"));
47
+            fileOutputStream.close();
48
+        } catch (Exception e) {
49
+            throw e;
50
+        }finally{
51
+            if(fileOutputStream != null){
52
+                fileOutputStream.close();
53
+            }
54
+        }
47 55
     }
48 56
 
49 57
     /**
@@ -58,29 +66,22 @@ public class ScriptUtil {
58 66
      * @param scriptFile
59 67
      * @param logFile
60 68
      */
61
-    public static void execToFile(String command, String scriptFile, String logFile){
62
-        try {
63
-            // 标准输出:print (null if watchdog timeout)
64
-            // 错误输出:logging + 异常 (still exists if watchdog timeout)
65
-            // 标准输出
66
-            FileOutputStream fileOutputStream = new FileOutputStream(logFile);
67
-            PumpStreamHandler streamHandler = new PumpStreamHandler(fileOutputStream, fileOutputStream, null);
69
+    public static void execToFile(String command, String scriptFile, String logFile) throws IOException {
70
+        // 标准输出:print (null if watchdog timeout)
71
+        // 错误输出:logging + 异常 (still exists if watchdog timeout)
72
+        // 标准输入
73
+        FileOutputStream fileOutputStream = new FileOutputStream(logFile, true);
74
+        PumpStreamHandler streamHandler = new PumpStreamHandler(fileOutputStream, fileOutputStream, null);
68 75
 
69
-            // command
70
-            CommandLine commandline = new CommandLine(command);
71
-            commandline.addArgument(scriptFile);
76
+        // command
77
+        CommandLine commandline = new CommandLine(command);
78
+        commandline.addArgument(scriptFile);
72 79
 
73
-            // exec
74
-            DefaultExecutor exec = new DefaultExecutor();
75
-            exec.setExitValues(null);
76
-            exec.setStreamHandler(streamHandler);
77
-            int exitValue = exec.execute(commandline);
78
-        } catch (Exception e) {
79
-            e.printStackTrace();
80
-        }
81
-        /*Process process = Runtime.getRuntime().exec(cmdarray);
82
-        IOUtils.copy(process.getInputStream(), out);
83
-        IOUtils.copy(process.getErrorStream(), out);*/
80
+        // exec
81
+        DefaultExecutor exec = new DefaultExecutor();
82
+        exec.setExitValues(null);
83
+        exec.setStreamHandler(streamHandler);
84
+        int exitValue = exec.execute(commandline);
84 85
     }
85 86
 
86 87
 }