运行命令时如何避免僵尸进程?

时间:2016-07-18 08:03:38

标签: rust iron

一个小铁项目在某个路线中调用Command并返回Response。以下是路由处理函数的相关代码:

fn convert(req: &mut Request) -> IronResult<Response> {

    // ...
    // init some bindings like destination_html and destination_pdf
    // ...

    convert_to_pdf(destination_html, destination_pdf);

    Ok( Response::with((status::Ok, "Done")) )
}

被调用函数的代码:

fn convert_to_pdf(destination_html: &str, destination_pdf: &str) {
    Command::new("xvfb-run")
        .arg("-a")
        .arg("wkhtmltopdf")
        .arg(destination_html)
        .arg(destination_pdf)
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .spawn()
        .expect("failed to execute process");
}

该过程有效(文件从HTML转换为PDF),响应将返回给浏览器。一切都很好,但作为我的应用程序的孩子,僵尸进程仍然存在:

enter image description here

我不知道为什么,我不知道如何避免它。 我该怎么办?

wkhtmltopdf命令是一个很长的过程,我不想同步调用它并等待它的返回。而且我不想每天两次重启我的Rust程序(僵尸孩子的父母)来杀死僵尸。

1 个答案:

答案 0 :(得分:1)

您的问题是您没有等待进程终止,因此操作系统不会释放任何资源(请参阅man pages for proper explanation)。你的僵尸正在记忆,这将导致资源枯竭。杀死父进程不会做任何事情,你需要手动杀死每个僵尸(如果你在一个线程中运行wkhtmltopdf,它会工作)。

除此之外......

您正在尝试生成命令并回答您的客户...甚至没有检查wkhtmltopdf的状态代码。此外,您以root身份运行,这是一个不好的做法(无论您是否以root身份开发)。并且您的应用程序容易受到DDoS的影响(如果您有很多客户端生成PDF,您的服务器将面临资源耗尽)。

(恕我直言)您应该将项目分成两部分:

  1. 没有渲染过程的服务器
  2. PDF渲染引擎
  3. 第一个会向第二个发送消息“请生成带有以下参数的PDF(..)”。第二个是查看消息队列,取第一个,生成PDF并等待完成/错误。您甚至可以在消息中添加唯一的#ID,并在呈现引擎上创建一个端点,以实际查询作业#ID的状态。

    您要做的是像Celery这样的作业队列,但它是用Python编写的,并且正在使用第三方软件(Redis)。