程序运行shell卡死?手动执行正常?

问题背景

之前碰到过一个奇葩的问题,在这里记录一下。

        首先我们的项目是微服务架构,很多功能都是需要执行一段shell命令来进行操作服务器,

有一次碰到功能执行一直处于运行中状态,查看日志也是只能看到去执行了shell命令。然后我们手动吧执行的shell命令拿出来在服务器上执行,发现是正常运行。这个问题困扰了好久。。。。

问题原因

        后续经过我的百度之旅,想到了一个原因,当然最后也确实也是这个原因。那就是我们在程序中通过Process运行shell命令导致的

Process process = Runtime.getRuntime().exec(shPath);

int exitCode = process .waitFor();

        Runtime.getRuntime()返回当前应用程序的Runtime对象,该对象的exec()方法指示Java虚拟机创建一个子进程执行指定的可执行程序,并返回与该子进程对应的Process对象实例。通过Process可以控制该子进程的执行或获取该子进程的信息。

        它的操作通过三个流(getOutputStream(),getInputStream(),getErrorStream())重定向到父进程。父进程使用这些流来提供到子进程的输入和获得从子进程的输出。因为输入和输出流提供有限的缓冲区大小,如果读写子进程的输出流或输入流出现失败,当缓冲区满之后将无法继续写入数据,则可能导致子进程阻塞,最终造成阻塞在waifor()这里。

问题解决

        知道这个问题之后解决起来就容易了,就是要清空getInputStream()getErrorStream()这两个流。而且两个流的清空一定是异步的。我在我们系统中是通过下面这种方式解决的

//线程池

private TaskThreadPoolConfig taskThreadPool = SpringContextUtil.getBean(TaskThreadPoolConfig.class);

    /**
     * 执行脚本方法
     *
     * @param sh
     */
    public Integer execShell(final String sh) throws Exception {
        final Process process = Runtime.getRuntime().exec(sh);
        // 方法阻塞,等待命令执行完成
        final int exitVal = process.waitFor();
        taskThreadPool.taskThreadPool().submit(new Runnable() {
            @Override
            public void run() {
                // 读取输出
                String line = null;
                try {
                    // 获取命令执行结果, 有两个结果: 正常的输出和错误的输出(PS: 子进程的输出就是主进程的输入)
                    BufferedReader bufrIn =
                            new BufferedReader(
                                    new InputStreamReader(process.getInputStream(), "UTF-8")); // 正常的输出
                    log.info("====="+line+"\n");
                    while ((line = bufrIn.readLine()) != null) {
                        log.info("====="+line+"\n");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        taskThreadPool.taskThreadPool().submit(new Runnable() {
            @Override
            public void run() {
                // 读取输出
                String line = null;
                try {
                    // 获取命令执行结果, 有两个结果: 正常的输出和错误的输出(PS: 子进程的输出就是主进程的输入)
                    BufferedReader bufrError  =
                            new BufferedReader(
                                    new InputStreamReader(process.getErrorStream(), "UTF-8")); // 错误的输出
                    log.info("====="+line+"\n");
                    while ((line = bufrError.readLine()) != null) {
                        log.info("====="+line+"\n");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        log.info("=========》》执行文件生成脚本结果:" + exitVal);
        return exitVal;
    }

这样就看到了我们程序卡住的原因居然是权限问题。。。。。。。

这样处理以后也能看到执行shell中具体的执行日志了,也能更好的排查问题。

  • 12
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值