关于Spring Batch 执行系统命令时进程阻塞的问题

Spring Batch提供了SystemCommandTasklet用来执行系统命令。底层使用JDK Runtime.exec()方法,Process.waitFor()来获取运行结果。

SystemCommandTasklet部分源码:

public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {

		FutureTask<Integer> systemCommandTask = new FutureTask<Integer>(new Callable<Integer>() {

			@Override
			public Integer call() throws Exception {
				Process process = Runtime.getRuntime().exec(command, environmentParams, workingDirectory);
                
				return process.waitFor();
			}

		});

		long t0 = System.currentTimeMillis();

		taskExecutor.execute(systemCommandTask);

		while (true) {
			Thread.sleep(checkInterval);
			if (systemCommandTask.isDone()) {
				contribution.setExitStatus(systemProcessExitCodeMapper.getExitStatus(systemCommandTask.get()));
				return RepeatStatus.FINISHED;
			}
			else if (System.currentTimeMillis() - t0 > timeout) {
				systemCommandTask.cancel(interruptOnCancel);
				throw new SystemCommandException("Execution of system command did not finish within the timeout");
			}
			else if (execution.isTerminateOnly()) {
				systemCommandTask.cancel(interruptOnCancel);
				throw new JobInterruptedException("Job interrupted while executing system command '" + command + "'");
			}
		}

	}
Process 的Javadoc写到:

The parent process uses these streams to feed input to and get output
from the subprocess.  Because some native platforms only provide
limited buffer size for standard input and output streams, failure
to promptly write the input stream or read the output stream of
the subprocess may cause the subprocess to block, or even deadlock.

SystemCommandTasklet没处理系统命令的输入输出。当输出大于系统限制缓冲区大小时,就会阻塞得不到返回。

例如我测试的在32位Windows下当输入超过512个字母时,进程被卡住不會结束。

修改使其处理执行系统命令时的输出(不太可能有输入所以没处理):

Process process = Runtime.getRuntime().exec(command, environmentParams, workingDirectory);
                final InputStream inputStream = process.getInputStream();
                final InputStream errorStream = process.getErrorStream();
                Runnable r1 = new Runnable() {

                    public void run() {
                        BufferedReader br = null;
                        try {
                            if (logger.isInfoEnabled()) {
                                br = new BufferedReader(new InputStreamReader(inputStream));
                                for (String read = br.readLine(); read != null; read = br.readLine()) {
                                    logger.info("Command out - " + read);
                                }
                            }
                        } catch (Exception e) {
                            logger.error(e.getMessage(), e);
                        } finally {
                            try {
                                if (br != null) {
                                    br.close();
                                }
                            } catch (IOException e1) {
                                // ignore
                            }
                        }
                    }
                };
                Runnable r2 = new Runnable() {

                    public void run() {
                        BufferedReader br = null;
                        try {
                            br = new BufferedReader(new InputStreamReader(errorStream));
                            for (String read = br.readLine(); read != null; read = br.readLine()) {
                                logger.error("Command error - " + read);
                            }
                        } catch (Exception e) {
                            logger.error(e.getMessage(), e);
                        } finally {
                            try {
                                if (br != null) {
                                    br.close();
                                }
                            } catch (IOException e1) {
                                // ignore
                            }
                        }
                    }
                };
                r1.run();
                r2.run();
		 return process.waitFor();

转载于:https://my.oschina.net/POintMELOve/blog/132374

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值