Python 生成进程的脚本无法在 systemd 下启动
Python script that spawns processes fails to start under systemd
我有一个 python 脚本,它定期扫描文件夹以供 ffmpeg 处理。我决定把它变成一个系统服务。脚本 运行 在命令行上运行良好,但当我尝试将其作为服务 运行 时抛出 BlockingIOError。为了弄清楚这个问题,我将脚本简化为一个几乎是 hello world 的例子,但我仍然得到相同的结果。这是我拥有的:
foobar.py
import subprocess
result = subprocess.run(['/usr/bin/ffmpeg', '-h'])
print(result)
foobar.service
[Unit]
Description=foobar
[Service]
Type=simple
TasksMax=1
User=root
Environment="PATH=/usr/bin:/root/24-7"
ExecStart=/usr/bin/python3.8 /root/24-7/foobar.py
异常
Aug 26 12:47:55 Ubuntu-1804-bionic-64-minimal systemd[1]: Started foobar.
Aug 26 12:48:15 Ubuntu-1804-bionic-64-minimal python3.8[4539]: Traceback (most recent call last):
Aug 26 12:48:15 Ubuntu-1804-bionic-64-minimal python3.8[4539]: File "/root/24-7/foobar.py", line 6, in <module>
Aug 26 12:48:15 Ubuntu-1804-bionic-64-minimal python3.8[4539]: result = subprocess.run(['/usr/bin/ffmpeg', '-h'])
Aug 26 12:48:15 Ubuntu-1804-bionic-64-minimal python3.8[4539]: File "/usr/lib/python3.8/subprocess.py", line 489, in run
Aug 26 12:48:15 Ubuntu-1804-bionic-64-minimal python3.8[4539]: with Popen(*popenargs, **kwargs) as process:
Aug 26 12:48:15 Ubuntu-1804-bionic-64-minimal python3.8[4539]: File "/usr/lib/python3.8/subprocess.py", line 854, in __init__
Aug 26 12:48:15 Ubuntu-1804-bionic-64-minimal python3.8[4539]: self._execute_child(args, executable, preexec_fn, close_fds,
Aug 26 12:48:15 Ubuntu-1804-bionic-64-minimal python3.8[4539]: File "/usr/lib/python3.8/subprocess.py", line 1637, in _execute_child
Aug 26 12:48:15 Ubuntu-1804-bionic-64-minimal python3.8[4539]: self.pid = _posixsubprocess.fork_exec(
Aug 26 12:48:15 Ubuntu-1804-bionic-64-minimal python3.8[4539]: BlockingIOError: [Errno 11] Resource temporarily unavailable
Aug 26 12:48:15 Ubuntu-1804-bionic-64-minimal systemd[1]: foobar.service: Main process exited, code=exited, status=1/FAILURE
Aug 26 12:48:15 Ubuntu-1804-bionic-64-minimal systemd[1]: foobar.service: Failed with result 'exit-code'.
不确定还可以尝试什么。我什至尝试用 sleep() 延迟调用,看看是否可能等待几秒钟会打开任何阻塞的东西。我不知道该尝试什么。有人知道吗?
问题是你的TasksMax=1
。这防止了子进程的分叉,并且效果并不特定于 subprocess.run
——任何诸如 subprocess.Popen
或 os.system
或 os.fork
甚至 non-Python 应用程序尝试分叉会遇到类似的问题。
这是 os.fork
在受到 TasksMax=1
影响时显示类似的症状:
foobar.py
import os
pid = os.fork()
if pid == 0:
print("child")
os._exit(0)
else:
print(os.waitpid(pid, 0))
Aug 26 12:25:57 moon systemd[1]: Started foobar.
Aug 26 12:25:57 moon python3.8[9477]: Traceback (most recent call last):
Aug 26 12:25:57 moon python3.8[9477]: File "/root/24-7/foobar.py", line 3, in <module>
Aug 26 12:25:57 moon python3.8[9477]: pid = os.fork()
Aug 26 12:25:57 moon python3.8[9477]: BlockingIOError: [Errno 11] Resource temporarily unavailable
Aug 26 12:25:57 moon systemd[1]: foobar.service: Main process exited, code=exited, status=1/FAILURE
Aug 26 12:25:57 moon systemd[1]: foobar.service: Failed with result 'exit-code'.
如果您删除该行或增加限制,它将起作用。
即使只是将它增加到 2 也适用于你简单的 ffmpeg -h
示例,尽管使用你想要的真实选项 运行,你可能想要增加它一点,只是如果 ffmpeg
需要 fork 自己的子进程。
我有一个 python 脚本,它定期扫描文件夹以供 ffmpeg 处理。我决定把它变成一个系统服务。脚本 运行 在命令行上运行良好,但当我尝试将其作为服务 运行 时抛出 BlockingIOError。为了弄清楚这个问题,我将脚本简化为一个几乎是 hello world 的例子,但我仍然得到相同的结果。这是我拥有的:
foobar.py
import subprocess
result = subprocess.run(['/usr/bin/ffmpeg', '-h'])
print(result)
foobar.service
[Unit]
Description=foobar
[Service]
Type=simple
TasksMax=1
User=root
Environment="PATH=/usr/bin:/root/24-7"
ExecStart=/usr/bin/python3.8 /root/24-7/foobar.py
异常
Aug 26 12:47:55 Ubuntu-1804-bionic-64-minimal systemd[1]: Started foobar.
Aug 26 12:48:15 Ubuntu-1804-bionic-64-minimal python3.8[4539]: Traceback (most recent call last):
Aug 26 12:48:15 Ubuntu-1804-bionic-64-minimal python3.8[4539]: File "/root/24-7/foobar.py", line 6, in <module>
Aug 26 12:48:15 Ubuntu-1804-bionic-64-minimal python3.8[4539]: result = subprocess.run(['/usr/bin/ffmpeg', '-h'])
Aug 26 12:48:15 Ubuntu-1804-bionic-64-minimal python3.8[4539]: File "/usr/lib/python3.8/subprocess.py", line 489, in run
Aug 26 12:48:15 Ubuntu-1804-bionic-64-minimal python3.8[4539]: with Popen(*popenargs, **kwargs) as process:
Aug 26 12:48:15 Ubuntu-1804-bionic-64-minimal python3.8[4539]: File "/usr/lib/python3.8/subprocess.py", line 854, in __init__
Aug 26 12:48:15 Ubuntu-1804-bionic-64-minimal python3.8[4539]: self._execute_child(args, executable, preexec_fn, close_fds,
Aug 26 12:48:15 Ubuntu-1804-bionic-64-minimal python3.8[4539]: File "/usr/lib/python3.8/subprocess.py", line 1637, in _execute_child
Aug 26 12:48:15 Ubuntu-1804-bionic-64-minimal python3.8[4539]: self.pid = _posixsubprocess.fork_exec(
Aug 26 12:48:15 Ubuntu-1804-bionic-64-minimal python3.8[4539]: BlockingIOError: [Errno 11] Resource temporarily unavailable
Aug 26 12:48:15 Ubuntu-1804-bionic-64-minimal systemd[1]: foobar.service: Main process exited, code=exited, status=1/FAILURE
Aug 26 12:48:15 Ubuntu-1804-bionic-64-minimal systemd[1]: foobar.service: Failed with result 'exit-code'.
不确定还可以尝试什么。我什至尝试用 sleep() 延迟调用,看看是否可能等待几秒钟会打开任何阻塞的东西。我不知道该尝试什么。有人知道吗?
问题是你的TasksMax=1
。这防止了子进程的分叉,并且效果并不特定于 subprocess.run
——任何诸如 subprocess.Popen
或 os.system
或 os.fork
甚至 non-Python 应用程序尝试分叉会遇到类似的问题。
这是 os.fork
在受到 TasksMax=1
影响时显示类似的症状:
foobar.py
import os
pid = os.fork()
if pid == 0:
print("child")
os._exit(0)
else:
print(os.waitpid(pid, 0))
Aug 26 12:25:57 moon systemd[1]: Started foobar.
Aug 26 12:25:57 moon python3.8[9477]: Traceback (most recent call last):
Aug 26 12:25:57 moon python3.8[9477]: File "/root/24-7/foobar.py", line 3, in <module>
Aug 26 12:25:57 moon python3.8[9477]: pid = os.fork()
Aug 26 12:25:57 moon python3.8[9477]: BlockingIOError: [Errno 11] Resource temporarily unavailable
Aug 26 12:25:57 moon systemd[1]: foobar.service: Main process exited, code=exited, status=1/FAILURE
Aug 26 12:25:57 moon systemd[1]: foobar.service: Failed with result 'exit-code'.
如果您删除该行或增加限制,它将起作用。
即使只是将它增加到 2 也适用于你简单的 ffmpeg -h
示例,尽管使用你想要的真实选项 运行,你可能想要增加它一点,只是如果 ffmpeg
需要 fork 自己的子进程。