2012-10-28 5 views
26

これは初心者の質問ですが、私はデーモンにとても謝っています。python-daemonでデーモンを設定するにはどうしたらいいですか?

他のいくつかの回答(たとえば、this question)では、人々はpython-daemonパッケージがPEP 3143標準を完全に実装しているために行く方法だと提案しました。

残念ながら、python-daemonはa bit light on documentationです(または、私は知識や経験について少し明るいです...))、私はおそらく本当に基本的なものを見逃していると思います。ここで私がやっているものです:

import daemon 

logfile = open('daemon.log', 'w') 

context = daemon.DaemonContext(stdout = logfile, stderr = logfile) 

context.open() 

with context: 
    do_something_1() 
    do_something_2() 

質問:次の私が持っている

を私のpython-デーモンとデーモンを設定するにはどうすればよい、どのように私はそれを開始し、それを止めることができますか?


サイドノート:

私は基本的に/か.open()方法は、ここで使用されるべきかについて野生の推測を取っている - ドキュメントはこの時点で本当の明確ではありませんでした。私はそれを含めるかどうかにかかわらず、同じことが起こるようです。

だから私は何をしますか?私は例えば、このファイルを実行しようとすると:

python startConsumerDaemons.py 

do_something_1()ではなく、第二の実行に表示されます。そして、端末ウィンドウにが添付されたままになります()。 IEでは、stdoutはリダイレクトされません。ターミナルウィンドウを閉じると、プロセスは強制終了されます。だから、私はここで間違っていると確信しています...どうすれば違うのでしょうか?

最後に、デーモンが実行されると、元のコードに変更を加えた場合など、どのように停止/再開するのですか?

$ ps -x 

をし、あなたのデーモンに対応して、ちょうどプロセスをkill PIDを見つける:

+0

行うことになってWITH' '最後は何ですか?(モジュールが最初にインポートされたときにモジュールが実行されますが、何かが欠落していない限り、最後のステートメントは何も行いません)。例外が発生しなかった場合、私は両方がうまく実行されたと確信しています。 – mgibsonbr

+0

"last"とはどういう意味なのか分かりませんが(ただ一つしかありません)、python-daemonのサンプルコードでは、そのようなwith文の中にデーモンとして実行するスクリプトを置きます(http:// www.python.org/dev/peps/pep-3143/)。最初のスクリプトが実行され、メッセージを受信/処理することができます(MQブローカー上のコンシューマー)。おそらくstartConsumerDaemonsスクリプトは決して2番目のスクリプトに到達しません。 – CQP

+0

あなたが投稿した例**は、別のファイル( 'initial_program_setup'、' do_main_program'など)からいくつかのメソッドをインポートし、**それらを 'with_'ステートメント内で**それらを呼び出す( 'do_main_program()') 。私が知りませんPythonのいくつかの曖昧な機能がない限り、私はそれらのステートメントは何もしないと確信しています。とにかく、私が理解できる限り、 'python-daemon'は現在実行中のプログラムをUNIXデーモンプロセスに変え、新しいプロセスや新しいスレッドを作成しません。プログラムの1つの部分が無限ループに入ると、後続の部分はまったく実行されません。 – mgibsonbr

答えて

0

Linux上で、あなたが実行してデーモンを停止することができます。

4

完全な例はavailable hereです。

あなたはpython-daemonの内部の仕組みをよりよく理解できるはずです。

さらに、提供されるコードは、単にデーモンを起動/停止するためのinitスクリプトの例を示しています。しかし、あなたはそれが単に引数ストップで再び元の関数を呼び出すことで開始/停止することができます

python original_func.py stop 
2

あなたが'with' statement documentationで見ることができるように、それは声明我々の目的に関連しているいくつかの「魔法」を、実行しません。

として一つの「項目」進むとwith文の実行は、以下:具体

  1. コンテキスト式(with_itemに与えられた式は)コンテキストマネージャを取得するために評価されます。

  2. コンテキストマネージャの__exit__()は、後で使用するためにロードされます。

  3. コンテキストマネージャの__enter__()メソッドが呼び出されます。

  4. ターゲットがwithステートメントに含まれていた場合、戻り値は__enter__()から割り当てられます。

  5. スイートが実行されます。

  6. コンテキストマネージャの__exit__()メソッドが呼び出されます。例外によりスイートが終了した場合、その型、値、および トレースバックが引数として__exit__()に渡されます。そうでなければ、3つのNone 引数が提供されます。

これは何を意味するのでしょうか?あなたが同様のpython-デーモンのドキュメントとして機能します(そして実際に改善ずっと可能性がある)the PEP in question、密接に見れば、あなたはそれが__enter__()__exit__()を実装していることがわかります:

クラスは、コンテキストマネージャを実装しますプロトコルは、__enter__ および__exit__の方法を介して行われる。

__enter__()

インスタンスを返し、その後、インスタンスのopen()メソッドを呼び出します。

__exit__(exc_type, exc_value, exc_traceback)

それがなかった場合は例外が処理またはFalseれた場合はTrueを返し、その後、インスタンスのclose()メソッドを呼び出します。

言い換えれば、open()は必要ではありません.PEPで指定された例は、正しく動作しませんが、そのまま動作します。 with文は何かを意味しますが、ループを保持しません。スコープの終わりに達すると出口()を呼び出します。これはpython-daemonではclose()を意味します。したがって、あなたは真実か、それともいつまでも無限ループと考えることができます。

あなたの2番目のスクリプトが動作しない場合、私は実際にあなたに話すことができません。私は最初の作品が驚いています。あなたのデーモンが停止している場合は、あなたのスクリプトに問題があります。あなたのconsumerDaemonLogFileを確認することができます。

また、指定されていなければ、作業ディレクトリのプロパティのデフォルトは「/」であることがPEPに示されています。これは、スクリプトで相対パスを使用している場合、問題の原因となる可能性があります。

最後に、最後の質問について、あなたは簡単にあなたがそのPIDを見つけデーモンいる殺すことができます。

ps ax | grep startConsumerDaemons.py 

とそれにSIGTERM送信:

kill <pid> 

gromainが提供する答えは提供しませんが'daemon.runner()'を使用して起動と停止を行うより便利な方法ですが、セットアップがはるかに複雑です。

-1

daemon.DaemonContextコンストラクタは、lockfileパラメータを受け入れます。 lockfile.PIDLockFileのように、プロセスのPIDを記録するロックファイル・ライブラリーを使用してください。

次に、名前付きPIDファイルの内容を読み取るだけで、プロセスのPIDが見つかります。そのPIDを使用して、実行中のデーモンに信号を送信します。

6

これは私が持っているものです。それは私のために働くものです。また、sysv initスクリプトもあります。 Repo is at GitHub、また私にはa brief blog postがあり、私が見つけた他の解決策へのリンクがあります。

ほとんどの他のLinuxデーモンと同様に、PIDロックファイルによって管理されるデーモンプロセスは1つしか実行できません。それを停止するには、それが実行されているかどうかを確認するには

kill `cat /var/run/eg_daemon.pid` 

の操作を行います。

ps -elf | grep `cat /var/run/eg_daemon.pid` 

pidファイルのサブモジュールを使用して、PIDファイルが自動的に管理されています。デーモンが停止すると、pidファイルはクリアされます。 initスクリプトのGitHubリポジトリを参照してください。ここでは、完全期すため

#!/usr/bin/env python3.5 
import sys 
import os 
import time 
import argparse 
import logging 
import daemon 
from daemon import pidfile 

debug_p = False 

def do_something(logf): 
    ### This does the "work" of the daemon 

    logger = logging.getLogger('eg_daemon') 
    logger.setLevel(logging.INFO) 

    fh = logging.FileHandler(logf) 
    fh.setLevel(logging.INFO) 

    formatstr = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' 
    formatter = logging.Formatter(formatstr) 

    fh.setFormatter(formatter) 

    logger.addHandler(fh) 

    while True: 
     logger.debug("this is a DEBUG message") 
     logger.info("this is an INFO message") 
     logger.error("this is an ERROR message") 
     time.sleep(5) 


def start_daemon(pidf, logf): 
    ### This launches the daemon in its context 

    ### XXX pidfile is a context 
    with daemon.DaemonContext(
     working_directory='/var/lib/eg_daemon', 
     umask=0o002, 
     pidfile=pidfile.TimeoutPIDLockFile(pidf), 
     ) as context: 
     do_something(logf) 


if __name__ == "__main__": 
    parser = argparse.ArgumentParser(description="Example daemon in Python") 
    parser.add_argument('-p', '--pid-file', default='/var/run/eg_daemon.pid') 
    parser.add_argument('-l', '--log-file', default='/var/log/eg_daemon.log') 

    args = parser.parse_args() 

    start_daemon(pidf=args.pid_file, logf=args.log_file) 

initスクリプトです:

はここでPythonのデーモンのコードです。 "kill"は実際にはPOSIXシグナルを送信するための単なる方法であることに注意してください - manページのsignal(7)の概要を参照してください。 pythonデーモンのコンテキストは、シグナルをキャッチし、プロセスを終了してファイル記述子をきれいに終了させ、PIDファイルを自動的に削除します。だから、本当にきれいな終了です。

デーモンの設定をリロードするために、SIGUSR1などを捕まえるためのコードを書くことができます。 Pythonを書くことはデーモンを止める利点はありません。

#!/bin/bash 
# 
# eg_daemon  Startup script for eg_daemon 
# 
# chkconfig: - 87 12 
# description: eg_daemon is a dummy Python-based daemon 
# config: /etc/eg_daemon/eg_daemon.conf 
# config: /etc/sysconfig/eg_daemon 
# pidfile: /var/run/eg_daemon.pid 
# 
### BEGIN INIT INFO 
# Provides: eg_daemon 
# Required-Start: $local_fs 
# Required-Stop: $local_fs 
# Short-Description: start and stop eg_daemon server 
# Description: eg_daemon is a dummy Python-based daemon 
### END INIT INFO 

# Source function library. 
. /etc/rc.d/init.d/functions 

if [ -f /etc/sysconfig/eg_daemon ]; then 
     . /etc/sysconfig/eg_daemon 
fi 

eg_daemon=/var/lib/eg_daemon/eg_daemon.py 
prog=eg_daemon 
pidfile=${PIDFILE-/var/run/eg_daemon.pid} 
logfile=${LOGFILE-/var/log/eg_daemon.log} 
RETVAL=0 

OPTIONS="" 

start() { 
     echo -n $"Starting $prog: " 

     if [[ -f ${pidfile} ]] ; then 
      pid=$(cat $pidfile ) 
      isrunning=$(ps -elf | grep $pid | grep $prog | grep -v grep) 

      if [[ -n ${isrunning} ]] ; then 
       echo $"$prog already running" 
       return 0 
      fi 
     fi 
     $eg_daemon -p $pidfile -l $logfile $OPTIONS 
     RETVAL=$? 
     [ $RETVAL = 0 ] && success || failure 
     echo 
     return $RETVAL 
} 

stop() { 
    if [[ -f ${pidfile} ]] ; then 
     pid=$(cat $pidfile) 
     isrunning=$(ps -elf | grep $pid | grep $prog | grep -v grep | awk '{print $4}') 

     if [[ ${isrunning} -eq ${pid} ]] ; then 
      echo -n $"Stopping $prog: " 
      kill $pid 
     else 
      echo -n $"Stopping $prog: " 
      success 
     fi 
     RETVAL=$? 
    fi 
    echo 
    return $RETVAL 
} 

reload() { 
    echo -n $"Reloading $prog: " 
    echo 
} 

# See how we were called. 
case "$1" in 
    start) 
    start 
    ;; 
    stop) 
    stop 
    ;; 
    status) 
    status -p $pidfile $eg_daemon 
    RETVAL=$? 
    ;; 
    restart) 
    stop 
    start 
    ;; 
    force-reload|reload) 
    reload 
    ;; 
    *) 
    echo $"Usage: $prog {start|stop|restart|force-reload|reload|status}" 
    RETVAL=2 
esac 

exit $RETVAL 
+0

まあ、 'kill'を使った' stop'メソッドはあまりいいことではありません... 'python mydaemon.py stop'などでそれを可能にすることはできませんか?さらに、デーモンの起動/停止に関する質問の中核部分のみを保持するように、例を単純化することもできます。 – Basj

+0

デーモンを処理する標準的なLinuxの方法です。インタラクティブなプロセスはありません。通信する唯一の方法は、Linuxの信号を使用することです。いくつかのPythonメソッドを使うと、killの呼び出しをラップすることになります。 –

0

「python-daemon」モジュールの有用なドキュメントはまだありません。私は個人的にそれを使用することをあきらめましたが、Sander Marechalのデーモンコードreferenced in this answerをうまく使用しました。

python testdaemon.py stopに電話すると、できることを少し修正しました。

Here is the code


使用例:

import sys, daemon, time 

class testdaemon(daemon.Daemon): 
    def run(self): 
     self.i = 0 
     with open('test1.txt', 'w') as f: 
      f.write(str(self.i)) 
     while True: 
      self.i += 1 
      time.sleep(1) 

    def quit(self): 
     with open('test2.txt', 'w') as f: 
      f.write(str(self.i)) 

daemon = testdaemon() 

if 'start' == sys.argv[1]: 
    daemon.start() 
elif 'stop' == sys.argv[1]: 
    daemon.stop() 
elif 'restart' == sys.argv[1]: 
    daemon.restart() 
関連する問題