Создайте демона с двойным форком в Ruby - PullRequest
26 голосов
/ 16 ноября 2009

Как правильно создать хорошо работающий демон Unix или Linux в Ruby?

Каково определение демона с хорошим поведением и как писать такую ​​программу на Ruby?

Ответы [ 2 ]

52 голосов
/ 16 ноября 2009

В соответствии с Расширенным программированием Стивенса в среде UNIX глава 13, это процедура для создания демона Unix с хорошим поведением:

  1. Вилка и родительский выход. Это заставляет оболочку или загрузочный скрипт думать, что команда выполнена. Кроме того, дочерний процесс гарантированно не будет лидером группы процессов (обязательным условием для setsid затем)
  2. Позвоните setsid, чтобы создать новый сеанс. Это делает три вещи:
    1. Процесс становится лидером сеанса нового сеанса
    2. Процесс становится лидером группы процессов новой группы процессов
    3. Процесс не имеет управляющего терминала
  3. При желании снова раскошелиться и получить родительский выход. Это гарантирует, что демон не является лидером сеанса и не может получить управляющий терминал (в соответствии с SVR4)
  4. Измените текущий рабочий каталог на /, чтобы не мешать подключению и отключению
  5. Установите маску создания режима файла равной 000, чтобы разрешить создание файлов с любым необходимым разрешением позже.
  6. Закрыть ненужные файловые дескрипторы, унаследованные от родительского (в любом случае управляющего терминала нет): stdout, stderr и stdin.

В настоящее время существует файл для отслеживания PID, который активно используется сценариями загрузки дистрибутива Linux. Обязательно запишите PID внука, либо возвращаемое значение второго форка (шаг 3), либо значение getpid() после шага 3.

Вот реализация 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
6 голосов
/ 17 марта 2012

Исходя из удивительного ответа Джейсона, я написал более полную реализацию здесь:

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

Я реализовал ведение журнала в дополнение к двойной ветке и записи pid в файл.

Еще одна интересная реализация в Unicorn:

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

...