生成进程的Python脚本无法在systemd下启动

问题描述

我有一个Python脚本,该脚本定期扫描文件夹以供ffmpeg处理。我决定将其转换为systemd服务。该脚本在命令行上运行良好,但是当我尝试将其作为服务运行时会抛出BlockingIOError。为了弄清楚问题,我将脚本简化为一个几乎打招呼的示例,但仍然得到相同的结果。这是我所拥有的:

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.Popenos.systemos.fork之类的东西,甚至非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'.

如果您删除该行或增加限制,那么它将起作用。

即使您使用简单的ffmpeg -h示例,即使将其增加到2也对我有用,尽管有了您要运行的实际选项,您可能还是希望将其增加一些,以防万一{{1} }需要派生自己的子进程。