web-dev-qa-db-ja.com

Pythonでデーモンをどのように作成しますか?

Googleで検索 x2コードスニペットが表示されます。最初の結果は このコードレシピ になります。これには、その下にある有用な説明とともに、多くのドキュメントと説明があります。

ただし、 別のコードサンプル には、あまりドキュメントがありませんが、start、stop、restartなどのコマンドを渡すためのサンプルコードが含まれています。また、デーモンがすでに実行されているかどうかなどをチェックするのに便利なPIDファイルも作成します。

これらのサンプルは両方ともデーモンの作成方法を説明しています。考慮する必要があるその他のものはありますか?あるサンプルは他のサンプルよりも優れていますか、そしてそれはなぜですか?

232
DavidM

現在の解決策

PEP 3143(標準デーモンプロセスライブラリ) の参照実装は python-daemon として利用可能になりました。

過去の回答

Sander Marechalの コードサンプル は、もともと2004年に投稿されたオリジナルよりも優れています。私はかつてPyroのデーモン化プログラムを提供しましたが、それをやり直さなければならない場合はおそらくSanderのコードを使用します。

152
Jeff Bauer

行儀の良いデーモンプロセスになるときに気をつけるべき面倒なことはたくさんあります

  • コアダンプを防止する(多くのデーモンはrootとして実行され、コアダンプには機密情報が含まれる可能性があります)

  • chroot gaol内で正しく動作する

  • ユースケースに合わせて、UID、GID、作業ディレクトリ、umask、およびその他のプロセスパラメータを適切に設定します。

  • 昇格されたsuidsgid特権を放棄する

  • ユースケースに応じて除外して、開いているすべてのファイル記述子を閉じます。

  • initinetdなど、すでに切り離されているコンテキスト内で起動した場合は正しく動作します。

  • 賢明なデーモンの振る舞いのためにシグナルハンドラを設定しますが、ユースケースによって決定された特定のハンドラも使用します

  • デーモンプロセスに制御端末がなくなったため、標準ストリームstdinstdoutstderrをリ​​ダイレクトします。

  • pIDファイルを協調的なアドバイザリロックとして扱う。これは それ自体でワームの全体的な可能性がある /多くの矛盾するが有効な振る舞いを伴う

  • プロセスが終了したときに適切なクリーンアップを許可する

  • 実際に ゾンビに導かずにデーモンプロセスになる

標準的なUNIXの文献( UNIX環境での高度なプログラミング)で説明されているように、これらのいくつかは標準です。後期W. Richard Stevens、Addison-Wesley、1992)。ストリームリダイレクションや PIDファイル処理 などの他のものは、ほとんどのデーモンユーザが期待する従来の動作ですが、標準化されていません。

これらすべてはPEP 3143 「標準デーモンプロセスライブラリ」仕様でカバーされています。 python-daemon reference実装は、Python 2.7以降、およびPython 3.2以降で動作します。

161
bignose

これは私が新しいデーモンアプリケーションを開発するときに使う私の基本的な 'Howdy World' Pythonデーモンです。

#!/usr/bin/python
import time
from daemon import runner

class App():
    def __init__(self):
        self.stdin_path = '/dev/null'
        self.stdout_path = '/dev/tty'
        self.stderr_path = '/dev/tty'
        self.pidfile_path =  '/tmp/foo.pid'
        self.pidfile_timeout = 5
    def run(self):
        while True:
            print("Howdy!  Gig'em!  Whoop!")
            time.sleep(10)

app = App()
daemon_runner = runner.DaemonRunner(app)
daemon_runner.do_action()

python-daemonライブラリが必要になるでしょう。あなたはそれをインストールすることができます:

pip install python-daemon

それから./howdy.py startで始めて、そして./howdy.py stopでそれを止めなさい。

92
Dustin Kirkland

箱から出してすぐにデーモンの背後にある多くの問題を解決する python-daemon パッケージに注意してください。

他の機能の中でも、(Debianパッケージの説明から):

  • プロセスを独自のプロセスグループに切り離します。
  • Chroot内での実行に適したプロセス環境を設定してください。
  • Suid特権とsgid特権を放棄します。
  • 開いているファイル記述子をすべて閉じます。
  • 作業ディレクトリ、uid、gid、およびumaskを変更します。
  • 適切なシグナルハンドラを設定してください。
  • Stdin、stdout、およびstderrの新しいファイル記述子を開きます。
  • 指定されたPIDロックファイルを管理します。
  • 出口処理用のクリーンアップ関数を登録します。
42
Viliam

別の方法 - 通常のデーモン化されていないPythonプログラムを作成してから、 supervisord を使用して外部的にデーモン化します。これは多くの頭痛の種を減らすことができ、そして* nixおよび言語移植可能です。

28
Chris Johnson

おそらく質問に対する直接的な答えではありませんが、systemdを使用してアプリケーションをデーモンとして実行することができます。これが一例です。

[Unit]
Description=Python daemon
After=syslog.target
After=network.target

[Service]
Type=simple
User=<run as user>
Group=<run as group group>
ExecStart=/usr/bin/python <python script home>/script.py

# Give the script some time to startup
TimeoutSec=300

[Install]
WantedBy=multi-user.target

多くの作業があなたのために行われ、そしてあなたのデーモンスクリプトがあなたのシステムの他の部分と同様に振る舞うので私はこの方法を好む。

- オービー

12
Luke Dupin

YapDi はHacker Newsに登場した比較的新しいpythonモジュールです。かなり便利に見えますが、Pythonスクリプトをスクリプト内からデーモンモードに変換するために使用できます。

6
Sergey R

python-daemonはpython 3.xをまだサポートしていないので、そしてメーリングリストで読むことができるものから、それは決してしないかもしれないので、私はPEP 3143の新しい実装を書きました: pep3143daemon

pep3143デーモンは少なくともpython 2.6、2.7および3.xをサポートするべきです。

PidFileクラスも含まれています。

ライブラリは標準ライブラリと6つのモジュールにのみ依存します。

これはpython-daemonに代わるドロップインとして使用できます。

これが ドキュメント です。

5

この関数はアプリケーションをデーモンに変換します。

import sys
import os

def daemonize():
    try:
        pid = os.fork()
        if pid > 0:
            # exit first parent
            sys.exit(0)
    except OSError as err:
        sys.stderr.write('_Fork #1 failed: {0}\n'.format(err))
        sys.exit(1)
    # decouple from parent environment
    os.chdir('/')
    os.setsid()
    os.umask(0)
    # do second fork
    try:
        pid = os.fork()
        if pid > 0:
            # exit from second parent
            sys.exit(0)
    except OSError as err:
        sys.stderr.write('_Fork #2 failed: {0}\n'.format(err))
        sys.exit(1)
    # redirect standard file descriptors
    sys.stdout.flush()
    sys.stderr.flush()
    si = open(os.devnull, 'r')
    so = open(os.devnull, 'w')
    se = open(os.devnull, 'w')
    os.dup2(si.fileno(), sys.stdin.fileno())
    os.dup2(so.fileno(), sys.stdout.fileno())
    os.dup2(se.fileno(), sys.stderr.fileno())
4
Ivan Kolesnikov

@Dustinによって言及されたデーモンモジュールが私のために働かなかったことを恐れています。代わりに python-daemon をインストールして以下のコードを使いました。

# filename myDaemon.py
import sys
import daemon
sys.path.append('/home/ubuntu/samplemodule') # till __init__.py
from samplemodule import moduleclass 

with daemon.DaemonContext():
    moduleclass.do_running() # I have do_running() function and whatever I was doing in __main__() in module.py I copied in it.

走りやすい

> python myDaemon.py

完全を期して、samplemoduleディレクトリの内容はここにあります

>ls samplemodule
__init__.py __init__.pyc moduleclass.py

Moduleclass.pyの内容は次のようになります。

class moduleclass():
    ...

def do_running():
    m = moduleclass()
    # do whatever daemon is required to do.
3
Somum

Pythonでデーモン化するときに考えるべきもう1つのこと:

あなたがpython loggingを使っていて、デーモン化した後もそれを使い続けたいのなら、ハンドラ(特にファイルハンドラ)でclose()を呼ぶようにしてください。

そうしなければ、ハンドラはまだファイルが開いていると考えることができ、メッセージは単に消えます。

これはあなたがデーモン化したときにすべての開いているファイルディスクリプタを無差別に閉じようとしていることを前提としています - 代わりにログファイル以外のすべてを閉じてみましょう.

2

私は、デーモンが停止する前に実行されるquit()メソッドを追加するために、Sander Marechalのコードサンプル( 受け入れられた答え の@JeffBauerによって言及されている)の数行を修正しました。これは時々とても便利です。

ここにあります

注:ドキュメントがまだ不足しているので(他の多くのSO質問も参照してください)、私は "python-daemon"モジュールを使用しません。このモジュールでコマンドラインから適切にデーモンを起動/停止しますか?)

1
Basj