3

Command一个小型 Iron 项目在某些路由中调用 a并返回 a 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)并将响应返回给浏览器。一切都很好,但是作为我的应用程序的子进程,僵尸进程仍然存在:

在此处输入图像描述

我不知道为什么,也不知道如何避免。我能做什么?

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

4

2 回答 2

2

您的问题是您没有等待进程终止,因此操作系统没有释放任何资源(请参阅手册页以获得正确的解释)。您的僵尸正在占用内存,这将导致资源耗尽。杀死父进程不会做任何事情,您需要手动杀死每个僵尸(如果您在线程中运行 wkhtmltopdf,它会起作用)。


除此之外...

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

(恕我直言)你应该把你的项目分成两个:

  1. 没有渲染过程的服务器
  2. PDF 渲染引擎

第一个将向第二个发送消息“请生成具有以下参数的 PDF (..)”。第二个将查看消息队列,获取第一个,生成 PDF 并等待完成/错误。您甚至可以在消息中添加一个唯一的#ID,并在渲染引擎上创建一个端点来实际查询作业#ID 的状态。

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

于 2016-07-18T09:18:58.837 回答
-1

这很难看,我讨厌它,它有效!

use std::{thread, time};


let _ = thread::spawn(|| {
    // Cull zombies every minute in the background
    loop {
        let minute = time::Duration::from_secs(60);
        thread::sleep(minute);
        println!("Culling Zombies");
        // 99999 FreeBSD
        // cat /proc/sys/kernel/pid_max Linux
        for pid in 1..99999 {
            let _ = nix::sys::wait::waitpid(nix::unistd::Pid::from_raw(pid as i32), Some(nix::sys::wait::WaitPidFlag::WNOHANG));
        }
    }
});
于 2021-01-14T21:02:30.533 回答