我可以使用Python异常来处理守护进程的SIGHUP信号吗?

2 投票
1 回答
1699 浏览
提问于 2025-04-16 10:57

我正在用Python写一个简单的文件同步程序,目的是在一台主机器和一台备用机器之间实现文件系统的同步。大部分复杂的工作都是由rsync来完成的。

在主机器那边,它会定期调用rsync,然后休眠几秒钟再重复这个过程。而在备用机器那边,它通过subprocess.Popen()启动rsyncd,并使用.wait()方法等待它结束。不过,我想通过发送一个SIGHUP信号来触发这个程序的重新配置。我在想,处理清理工作最好的方法是什么。

我最初的想法是让信号处理器抛出一个异常,这样就可以触发清理工作:

def signal_handler(signum, frame):
    raise fsync_config_exception

还有:

rsync_args = [rsync_binary, "--daemon", "--no-detach", "--config=%s" % (config.name) ]
p = subprocess.Popen(rsync_args)
try:
    p.wait()
    if p.returncode != 0:
        print "failed to spawn rsyncd"
        return False
except fsync_config_exception:
    print "spawn_and_monitor_rsyncd: config exceptions"
except:
    (type, value, tb) = sys.exc_info()
    print "we got %s with %s instead" % (type, value)

但是我遇到了一个:

we got <type 'exceptions.TypeError'> with __init__() takes exactly 2 arguments (1 given) instead

而不是我预期的fsync_config_exception。有没有人对处理这种问题有什么好的建议?我是不是在信号上下文中错误地使用了异常?

1 个回答

2

你应该抛出一个 fsync_config_exception 的实例,而不是类本身。也就是说,要用它的 __init__() 方法来创建一个对象。

不过,我不建议你以这种方式抛出异步异常。这样做很难保证异常只在可以正确处理的时候被抛出。而且,这种做法也不太好,因为在Python解释器中,你无法中断阻塞的C扩展调用……(但这对你来说可能不是问题?)

在信号处理程序中,我会(简单说一下细节,不确定这是否适合你的情况):

  • 设置状态,标记当前的迭代已经被中断——用这个来判断是否需要进行特殊的清理工作
  • 在信号处理程序中,终止你正在等待的进程
  • 在等待之后再加一个条件检查,看看进程是否是被信号杀掉的(同时检查状态变量,看看是否收到了SIGHUP信号)
  • 根据SIGHUP信号做你需要做的事情

撰写回答