为什么在使用supervisord运行的进程中stdout不刷新?

5 投票
2 回答
3072 浏览
提问于 2025-04-17 19:20

我正在使用Supervisor(一个用Python写的进程管理工具)来启动和控制我的网页服务器及相关服务。有时候我需要进入pdb(其实是ipdb)来调试正在运行的服务器,但通过Supervisor实现这一点有点困难。

Supervisor通过一个叫做supervisord的守护进程来启动和控制进程,并通过一个叫做supervisorctl的客户端提供访问。这个客户端允许你用'fg'命令连接到一个已经启动的前台进程。比如这样:

supervisor> fg webserver

所有的日志数据都会发送到终端。但是我没有从pdb调试器那里收到任何文本。虽然它能接受我的输入,所以标准输入(stdin)似乎是正常工作的。

在我的调查过程中,我确认了printraw_input都没有发送任何文本出去;不过在raw_input的情况下,标准输入确实是正常的。

我还确认了这个是可以工作的:

sys.stdout.write('message')
sys.flush()

我原以为当我发出fg命令时,就像是在标准终端中运行进程一样……但看起来supervisorctl做了一些额外的事情。例如,普通的打印输出并没有被刷新。有什么想法吗?

我该如何在使用supervisorctl的fg命令连接到前台终端时,让pdb、标准打印等正常工作?

(可能有用的参考链接:http://supervisord.org/subprocess.html#nondaemonizing-of-subprocesses)

2 个回答

0

可能你的网络服务器把自己的输出(也就是它内部的日志信息)直接转到一个日志文件里了,也就是说它不管 supervisord 是怎么处理输出的,这样就导致 supervisord 无法控制输出的去向。

你可以用 tail -f 命令来查看这个日志,看看你在终端里期待看到的输出是不是出现在那里。

如果确实是这样,试着找找有没有办法配置你的网络服务器,让它不要这样做。要是实在找不到办法,可以考虑用两个终端来操作……一个用来输入,另一个用来查看输出。

8

原来,Python 默认会对它的输出进行缓冲处理。在某些情况下(比如这个例子),这会导致输出被延迟显示。

有一些方法可以解决这个问题:

sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

可以强制将缓冲区设置为零。

但我觉得更好的办法是,在启动 Python 程序时使用 -u 这个选项,这样就可以让它在不进行缓冲的状态下运行。在 supervisord.conf 文件中,只需要这样写:

command=python -u script.py

参考链接:http://docs.python.org/2/using/cmdline.html#envvar-PYTHONUNBUFFERED

另外要注意,这样做会让你的日志文件变得杂乱,特别是如果你使用了像 ipdb 这样的工具并且启用了 ANSI 颜色。不过因为这是开发环境,所以这可能并不重要。

如果这成为一个问题,另一种解决办法是先在 supervisorctl 中停止需要调试的进程,然后在另一个终端中临时运行这个进程进行调试。这样可以保持日志文件的整洁,如果你需要的话。

撰写回答