DaemonContextでpythonスクリプトをデーモン化する

pythonでデーモンを書きたいと思って、調べてみると「Pythonでprefork型のデーモンを書く」という記事を見つけました。この内容が素晴しくて、プロセスもデーモンも初心者な僕でも処理の大枠を理解できました。
それで、デーモン化する為のモジュールってあるんじゃないのと思いpypiを見てみると、複数のモジュールが登録されていました。その中で一番リッチな機能を持つDaemonContextを使ってみる事にしました。

インストールはeasy_installで一発です。

$ easy_install python-daemon

使い方も簡単でDaemonContextオブジェクトを作成して、そのwith構文中がDaemon化されます。

#!/usr/bin/python
# -*- coding: utf-8 -*-

from __future__ import with_statement
from daemon import DaemonContext

dc = DaemonContext()
with dc:
  # withの中がデーモン化される
  do_some_task() 

機能もリッチです。僕が便利だと感じているのは、pidファイルの指定と標準入出力先のリダイレクトです。これらの機能はDaemonContextのコンストラクタにパラメータを指定することで使用できます。先ほどのサンプルで上記の2機能を使うと以下のようになります。

#!/usr/bin/python
# -*- coding: utf-8 -*-

from __future__ import with_statement
from daemon import DaemonContext
from daemon.pidlockfile import PIDLockFile

dc = DaemonContext(
  pidfile=PIDLockFile('/tmp/mydaemon.pid'),
  stderr=open('fake_err_console.txt', 'w+')
)
with dc:
  # withの中がデーモン化される
  do_some_task()

これでデーモンのpidが記述されたファイルが/tmp/mydaemon.piに作成されます。デーモンをkillする際はkill `cat /tmp/mydaemon.pid`と書く事が出来ますね。
また標準エラー出力をfake_err_console.txtに設定しています。スクリプトをデーモン化すると、プロセスがターミナルからデタッチされるのでデバッグがしにくいのですが、これで最低限のデバッグは出来るようになります。他にも機能が1通りそろっているので、ソースのクラス定義を1度眺めてみても良いと思います。

ただ問題が1つあって、マルチプロセスなデーモンを作ろうとすると、先日のエントリの話と同じで、DaemonContextがatexitメソッドを使ってpidファイルの削除処理を実装しているため、子プロセスの終了時にpidファイルが削除されてしまい、肝心の親プロセスをkillする際にはpidファイルが残ってません。

というわけでマルチプロセスなデーモンを使う際はpidファイルの処理は自前で実装する必要がありますが、それ以外のデーモン化ならこのモジュールは非常に便利ですね。

1 thought on “DaemonContextでpythonスクリプトをデーモン化する”

  1. 本文で指摘されている問題とは直接関係ありませんが、DatemonContext()にuidを引き渡した場合、rootでスクリプトを起動、setuid(uid)した後でpidfile.__enter__が実行される設計にも問題があります。例えばPIDLockFileだと指定されたディレクトリがそのユーザで読み書きできないとエラーになります。root所有の/var/runを使いたくても使えません。なのでこの場合もpidファイルの処理を自前で実装する必要があります

Leave a Reply

Your email address will not be published. Required fields are marked *