简介
python-daemon实现Unix守护进程。 参考:PEP 3143
该库实现了PEP 3143“标准守护进程库”的良好行为守护进程规范。
DaemonContext实例保存程序的行为和配置的进程环境。
快速入门
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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)
|
执行:
1 2 3 4 5 6 7 8 9 10 11 12 | $ 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打开文件的方式。
1 2 3 4 5 6 7 | # 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)
|
更实用的例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 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()
|
执行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | $ 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
|
注意上面的错误是重复启动或者停止时进程并不存在导致的。
参考资料
本文代码地址: http://t.cn/R8scWAe
-
技术支持 (可以加钉钉pythontesting邀请加入) qq群:144081101 591302926 567351477
-
道家技术-手相手诊看相中医等钉钉群21734177 qq群:391441566 184175668 338228106 看手相、面相、舌相、抽签、体质识别。服务费50元每人次起。请联系钉钉或者微信pythontesting
接口自动化性能测试数据分析人工智能从业专家一对一线上培训大纲
daemonize demo无法运行
https://pypi.python.org/pypi/python-daemon
老式书写后台进程的一种方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | $ 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注册为后台进程。