使用python-daemon实现守护进程时未生成pidfile的解决方法
解决python-daemon守护进程不生成PID文件的问题
核心问题分析
你遇到的PID文件未生成情况,主要集中在权限不足、PID文件类使用不当以及代码潜在异常导致进程提前退出这几个方面,以下是针对性解决方案:
1. 解决权限问题
/var/run目录默认属于root用户,普通用户无写入权限,这是最常见的原因。你有两个选择:
- 以root身份启动守护进程(比如用
sudo) - 将PID文件路径改为普通用户有权限的目录,例如
~/run/test.pid(需先手动创建~/run目录)
2. 修正代码中的潜在异常
原代码中Runner类的terminate方法会访问self.timer,但第一次调用scheduleNextRun前该属性未初始化,会触发AttributeError导致进程异常退出,PID文件被自动清理。需要在类初始化时默认初始化self.timer:
class Runner: def __init__(self): self.timer = None # 提前初始化timer属性,避免终止时触发异常 def run(self): syslog.syslog("Running something") def scheduleNextRun(self): self.run() self.timer = threading.Timer(3, self.scheduleNextRun) self.timer.start() def terminate(self, signum, frame): syslog.syslog("Received {}".format(signal.Signals(signum).name)) if self.timer: syslog.syslog("Stopping the timer") self.timer.cancel() syslog.syslog("Will now terminate")
3. 正确使用python-daemon自带的PID文件类
使用daemon.pidfile.PIDLockFile是规范方式,需确保DaemonContext正确管理文件生命周期。修正后的完整代码如下:
import daemon import daemon.pidfile import threading import syslog import signal import os class Runner: def __init__(self): self.timer = None def run(self): syslog.syslog("Running something") def scheduleNextRun(self): self.run() self.timer = threading.Timer(3, self.scheduleNextRun) self.timer.start() def terminate(self, signum, frame): syslog.syslog("Received {}".format(signal.Signals(signum).name)) if self.timer: syslog.syslog("Stopping the timer") self.timer.cancel() syslog.syslog("Will now terminate") os._exit(0) # 确保进程正常退出 def setup(): runner = Runner() signal.signal(signal.SIGTERM, runner.terminate) signal.signal(signal.SIGINT, runner.terminate) runner.scheduleNextRun() # 阻塞主线程,避免DaemonContext提前退出 while True: threading.Event().wait(1) # 示例:使用root权限路径或普通用户可写路径 pid_file_path = "/var/run/test.pid" # pid_file_path = os.path.expanduser("~/run/test.pid") # 确保PID文件所在目录存在 pid_dir = os.path.dirname(pid_file_path) if not os.path.exists(pid_dir): os.makedirs(pid_dir, exist_ok=True) with daemon.DaemonContext( pidfile=daemon.pidfile.PIDLockFile(pid_file_path), working_directory="/tmp" # 指定工作目录,避免影响原环境 ): setup()
关键补充说明
- DaemonContext会在进程正常退出时自动清理PID文件,若进程因异常崩溃,PID文件也会被删除,这是正常行为。可通过查看syslog日志排查进程是否异常退出。
- 优先使用python-daemon自带的
daemon.pidfile模块,第三方PID文件库需实现acquire()和release()接口才能被DaemonContext正确管理。
内容的提问来源于stack exchange,提问作者Tobias Leupold
相关产品推荐
相关产品推荐

