python庫介紹-python-daemon: 實現python後臺程式的工具
簡介
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 Feb8 14:21:43 2018 $ ps afx | grep -i daemon1 8646 pts/2S+0:00|\_ grep --color=auto -i daemon1 8640 ?S0: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)
更實用的例子
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.pystart 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.pystop Terminating on signal 15 andrew@andrew-MS-7A71:~/code/python-chinese-library/libraries/daemon$ python3 daemon2.pystop 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
注意上面的錯誤是重複啟動或者停止時程序並不存在導致的。
參考資料
- 討論qq群144081101 591302926 567351477 釘釘免費群21745728
- 本文相關書籍下載
- 本文涉及的python測試開發庫 謝謝點贊!
- 本文程式碼地址
- 本文最新版本地址
- daemonize demo無法執行
- https://pypi.python.org/pypi/python-daemon
老式書寫後臺程序的一種方式
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註冊為後臺程序。