开机启动的程序无法访问 /run/user/1000

Program started on boot cannot access /run/user/1000

我有一个关于 Python (3) 程序正在由 systemd 启动的有趣错误的问题。这一切都发生在 Raspberry Pi 零 运行 完全更新 Raspberry Pi OS 上。它是 Google AIY Voice Kit v2 的大脑,尽管它在这里似乎并不是特别重要。

有问题的 systemd 服务运行我的 Python 程序,该程序调用 aiy.voice.tts.say("Example text")。然而,这个 returns a FileNotFoundError - 完整的回溯是:

May 28 21:50:11 voicekit-zero autostart.sh[620]: Traceback (most recent call last):
May 28 21:50:11 voicekit-zero autostart.sh[620]:   File "/home/pi/ready.py", line 27, in <module>
May 28 21:50:11 voicekit-zero autostart.sh[620]:     """, volume=5)
May 28 21:50:11 voicekit-zero autostart.sh[620]:   File "/home/pi/AIY-projects-python/src/aiy/voice/tts.py", line 52, in say
May 28 21:50:11 voicekit-zero autostart.sh[620]:     with tempfile.NamedTemporaryFile(suffix='.wav', dir=RUN_DIR) as f:
May 28 21:50:11 voicekit-zero autostart.sh[620]:   File "/usr/lib/python3.7/tempfile.py", line 686, in NamedTemporaryFile
May 28 21:50:11 voicekit-zero autostart.sh[620]:     (fd, name) = _mkstemp_inner(dir, prefix, suffix, flags, output_type)
May 28 21:50:11 voicekit-zero autostart.sh[620]:   File "/usr/lib/python3.7/tempfile.py", line 397, in _mkstemp_inner
May 28 21:50:11 voicekit-zero autostart.sh[620]:     fd = _os.open(file, flags, 0o600)
May 28 21:50:11 voicekit-zero autostart.sh[620]: FileNotFoundError: [Errno 2] No such file or directory: '/run/user/1000/tmponnl3w02.wav'

从这个回溯中可以很清楚地看出,TTS 脚本将 WAV 文件写入 /run/user/1000/ 中的临时位置,然后将其用于播放。然而,到那时,该文件已变得无法访问。我最好的猜测是文件系统还没有完全初始化。 (我不确定这一点,而且我对 systemd 服务没有那么多经验,所以我肯定是错的。)

systemd 服务文件为 network-online.targetsystemd-timesyncd.service 指定了 WantsAfter,当然这些都与文件系统准备就绪没有直接关系。之后我可以启动另一项服务以确保文件系统已准备好进行此调用吗?如果没有,我可以等几秒钟,但我更愿意构建一个应该可靠运行的更强大的系统。

谢谢!

在我填写了一些遗漏的细节后,这个问题比我预期的要容易。

首先,这不是 Python 的问题,也不是安装文件系统的延迟 - 它集中在相关用户的(在本例中,pi,其 UID 1000) 运行时的登录状态。我发现如果我通过 SSH 登录,问题错误消失了。

研究使我 loginctl enable-linger:

Enable/disable user lingering for one or more users. If enabled for a specific user, a user manager is spawned for the user at boot and kept around after logouts. This allows users who are not logged in to run long-running services. Takes one or more user names or numeric UIDs as argument. If no argument is specified, enables/disables lingering for the user of the session of the caller.

运行 仅此命令即可解决问题。