28

在 Ruby 中创建行为良好的 Unix 或 Linux 守护程序的正确方法是什么?

无论如何,行为良好的守护进程的定义是什么,如何用 Ruby 编写这样的程序?

4

2 回答 2

54

根据 Stevens 的UNIX 环境中的高级编程第 13 章,这是制作表现良好的 Unix 守护进程的过程:

  1. 分叉并让父级退出。这使 shell 或引导脚本认为命令已完成。另外,保证子进程不是进程组长(setsid next 的先决条件)
  2. 调用setsid以创建新会话。这做了三件事:
    1. 该进程成为新会话的会话负责人
    2. 进程成为新进程组的进程组长
    3. 该进程没有控制终端
  3. 可以选择再次分叉并让父级退出。这保证了守护进程不是会话领导者,也不能获取控制终端(在 SVR4 下)
  4. 更改当前工作目录以/避免干扰挂载和卸载
  5. 将文件模式创建掩码设置为 000 以允许稍后创建具有任何所需权限的文件。
  6. 关闭从父级继承的不需要的文件描述符(反正没有控制终端):stdoutstderrstdin.

现在有一个文件可以跟踪被 Linux 发行版引导脚本大量使用的 PID。一定要写出孙子的PID,要么是第二个fork(第3步)的返回值,要么是第3getpid()步之后的值。

这是一个 Ruby 实现,大部分是从书中翻译过来的,但是带有双叉并写出守护进程 PID。

# Example double-forking Unix daemon initializer.

raise 'Must run as root' if Process.euid != 0

raise 'First fork failed' if (pid = fork) == -1
exit unless pid.nil?

Process.setsid
raise 'Second fork failed' if (pid = fork) == -1
exit unless pid.nil?
puts "Daemon pid: #{Process.pid}" # Or save it somewhere, etc.

Dir.chdir '/'
File.umask 0000

STDIN.reopen '/dev/null'
STDOUT.reopen '/dev/null', 'a'
STDERR.reopen STDOUT
于 2009-11-16T05:54:07.487 回答
6

继 Jason 的精彩回应之后,我在这里编写了一个更完整的实现:

https://gist.github.com/1372491/b76b60fb1842bf0507f47869ab19ad50a045b214

除了双叉和将 pid 写入文件之外,我还实现了日志记录。

另一个有趣的实现是在 Unicorn 中:

https://github.com/defunkt/unicorn/blob/master/lib/unicorn/launcher.rb

于 2012-03-17T03:10:56.890 回答