美文网首页工具癖软件测试Python专家之路程序员
python库介绍-python-daemon: 实现pytho

python库介绍-python-daemon: 实现pytho

作者: python测试开发 | 来源:发表于2018-09-17 23:13 被阅读88次

    简介

    python-daemon实现Unix守护进程。 参考:PEP 3143

    该库实现了PEP 3143“标准守护进程库”的良好行为守护进程规范。

    DaemonContext实例保存程序的行为和配置的进程环境。

    快速入门

    
    import time
    
    with daemon.DaemonContext():
        f = open("/tmp/test.log",'w')
        while True:
            f.write('''
            Library to implement a well-behaved Unix daemon process.
    
    This library implements the well-behaved daemon specification of PEP 3143, “Standard daemon process library”.
    
    A well-behaved Unix daemon process is tricky to get right, but the required steps are much the same for every daemon program. A DaemonContext instance holds the behaviour and configured process environment for the program; use the instance as a context manager to enter a daemon state.
    ''')
            f.write("{0}\n".format(time.ctime(time.time())))
            time.sleep(1)
    

    执行:

    
    $ python3 daemon1.py 
    
    $ tail -f /tmp/test.log 
    This library implements the well-behaved daemon specification of PEP 3143, “Standard daemon process library”.
    
    A well-behaved Unix daemon process is tricky to get right, but the required steps are much the same for every daemon program. A DaemonContext instance holds the behaviour and configured process environment for the program; use the instance as a context manager to enter a daemon state.
    Thu Feb  8 14:21:43 2018
    
    $ ps afx | grep -i daemon1
     8646 pts/2    S+     0:00          |           \_ grep --color=auto -i daemon1
     8640 ?        S      0:00          \_ python3 daemon1.py
    $ kill -9 8640
    
    

    要想停止上述进程,可以通过ps查找到进程号,然后kill。

    注意上述代码在python2没有任何问题,不过在python需要修改库文件runner.py打开文件的方式。

    
    # vi /usr/local/lib/python3.5/dist-packages/daemon/runner.py 
    # 118 -120
            self.daemon_context = DaemonContext()
            self.daemon_context.stdin = open(app.stdin_path, 'wb+',buffering=0)
            self.daemon_context.stdout = open(app.stdout_path,  'wb+',buffering=0)
            self.daemon_context.stderr = open(
                    app.stderr_path, 'wb+', buffering=0)
    

    更实用的例子

    #讨论钉钉免费群21745728qq群144081101 567351477
    import time
    import logging
    import logging.handlers
    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):
            
            logs = logging.getLogger('MyLogger')
            logs.setLevel(logging.DEBUG)
            fh = logging.handlers.RotatingFileHandler(
                '/tmp/test.log',maxBytes=10000000,backupCount=5)
            fh.setLevel(logging.DEBUG)
            formatter = logging.Formatter(u'%(asctime)s [%(levelname)s] %(message)s')
            fh.setFormatter(formatter)
            logs.addHandler(fh)  
            
            while True:
                for i in range(10):
                    logs.info("Beginning Scan {0}! \n".format(i))
                time.sleep(1)
    
    app = App()
    daemon_runner = runner.DaemonRunner(app)
    daemon_runner.do_action()
    

    执行:

    
    $ python2 daemon2.py 
    usage: daemon2.py start|stop|restart
    
    $ python3 daemon2.py  start
    andrew@andrew-MS-7A71:~/code/python-chinese-library/libraries/daemon$ 
    andrew@andrew-MS-7A71:~/code/python-chinese-library/libraries/daemon$ Traceback (most recent call last):
      File "/usr/local/lib/python3.5/dist-packages/lockfile/pidlockfile.py", line 77, in acquire
        write_pid_to_pidfile(self.path)
      File "/usr/local/lib/python3.5/dist-packages/lockfile/pidlockfile.py", line 161, in write_pid_to_pidfile
        pidfile_fd = os.open(pidfile_path, open_flags, open_mode)
    FileExistsError: [Errno 17] File exists: '/tmp/foo.pid'
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "daemon2.py", line 39, in <module>
        daemon_runner.do_action()
      File "/usr/local/lib/python3.5/dist-packages/daemon/runner.py", line 274, in do_action
        func(self)
      File "/usr/local/lib/python3.5/dist-packages/daemon/runner.py", line 182, in _start
        self.daemon_context.open()
      File "/usr/local/lib/python3.5/dist-packages/daemon/daemon.py", line 389, in open
        self.pidfile.__enter__()
      File "/usr/local/lib/python3.5/dist-packages/lockfile/__init__.py", line 197, in __enter__
        self.acquire()
      File "/usr/local/lib/python3.5/dist-packages/daemon/pidfile.py", line 60, in acquire
        super(TimeoutPIDLockFile, self).acquire(timeout, *args, **kwargs)
      File "/usr/local/lib/python3.5/dist-packages/lockfile/pidlockfile.py", line 85, in acquire
        self.path)
    lockfile.LockTimeout: Timeout waiting to acquire lock for /tmp/foo.pid
    
    andrew@andrew-MS-7A71:~/code/python-chinese-library/libraries/daemon$ python3 daemon2.py  stop
    Terminating on signal 15
    andrew@andrew-MS-7A71:~/code/python-chinese-library/libraries/daemon$ python3 daemon2.py  stop
    Traceback (most recent call last):
      File "daemon2.py", line 39, in <module>
        daemon_runner.do_action()
      File "/usr/local/lib/python3.5/dist-packages/daemon/runner.py", line 274, in do_action
        func(self)
      File "/usr/local/lib/python3.5/dist-packages/daemon/runner.py", line 224, in _stop
        raise error
    daemon.runner.DaemonRunnerStopFailureError: PID file '/tmp/foo.pid' not locked
    
    

    注意上面的错误是重复启动或者停止时进程并不存在导致的。

    参考资料

    老式书写后台进程的一种方式

    
    import time
    import logging
    import logging.handlers
    
    
    logs = logging.getLogger('MyLogger')
    logs.setLevel(logging.DEBUG)
    fh = logging.handlers.RotatingFileHandler(
        '/tmp/test.log',maxBytes=10000000,backupCount=5)
    fh.setLevel(logging.DEBUG)
    formatter = logging.Formatter(u'%(asctime)s [%(levelname)s] %(message)s')
    fh.setFormatter(formatter)
    logs.addHandler(fh)  
    
    
    while True:
        for i in range(10):
            logs.info("Beginning Scan {0}! \n".format(i))
        time.sleep(1)      
    

    这样并不能后台执行,但是可以借助linux的nohup和&。为此添加如下的启动和停止脚本,其实也不麻烦:

    shell脚本参见: http://t.cn/R8scWAe

    
    $ sh startup.sh 
    ================================================================================================================
    Starting older.py(PID=15315)...[Success]
    ================================================================================================================
    $ sh startup.sh 
    ================================================================================================================
    older.py already started(PID=15315)
    ================================================================================================================
    $ sh shutdown.sh 
    ================================================================================================================
    Stopping older.py(PID=15315)...[Success]
    ================================================================================================================
    $ sh shutdown.sh 
    ================================================================================================================
    older.py is not running
    ================================================================================================================
    
    

    其他

    supervisord 可以linux控制linux进程,当然也可以后台化。

    How do you create a daemon in Python?

    另外也可以向linux systemd注册为后台进程。

    相关文章

      网友评论

        本文标题:python库介绍-python-daemon: 实现pytho

        本文链接:https://www.haomeiwen.com/subject/gkyjnftx.html