广泛搜索,许多相关问题,但我发现没有一个真正有效。
所以我有一个 shell 脚本,我想通过 systemd 服务实现自动化。剧本:
#!/usr/bin/env bash
SESSION="daemon"
DAEMON_WINDOW="daemon"
CLIENT_WINDOW="client"
tmux new-session -d -s $SESSION
tmux rename-window -t 0 $DAEMON_WINDOW
tmux send-keys -t $DAEMON_WINDOW 'cd $HOME/work/gastd' C-m './gastd' C-m
sleep 30
tmux new-window -t $SESSION:1 -n $CLIENT_WINDOW
tmux send-keys -t $CLIENT_WINDOW 'gast-client' C-m
tmux attach-session -t $SESSION:1
好的,从 shell 运行时可以正常工作。基本上它在一个窗口中启动守护进程。守护进程会初始化一些东西,所以我必须等待,在睡眠后,我与客户端一起启动第二个窗口。
现在,当我作为 systemd 运行时,它实际上似乎启动正常,然后失败退出。
我认为原因很简单:一切都运行完毕,然后脚本终止,因此 systemd 假设它终止并存在该服务 - 杀死 tmux 会话和窗口,这是真正的问题。
目标是保持会话和窗口永远运行,除非我运行 systemctl stop service。
我可以在脚本末尾添加一个无限循环,但这看起来不太好。
有没有更好的办法?我尝试过,Type=forking
但这也没有帮助,最后还因为某种原因崩溃了。
这是我当前的 systemd 脚本:
[Unit]
Description=gast daemon
[Service]
ExecStart=/home/gastuser/start-tmux-session.sh
WorkingDirectory=/home/gastuser/work/gastd
User=gastuser
StandardOutput=file:/home/gastuser/.gast/gast.log
StandardError=file:/home/gastuser/.gast/gast.log
Restart=on-failure
[Install]
WantedBy=multi-user.target
我真的进行了广泛的搜索,如果问题/答案已经存在,抱歉。
答案1
读自文档:
systemd 的简单服务类型如下:
oneshot
是一个在短时间内运行完成然后完全退出的服务。
simple
是一个在前台运行的程序。因此,systemd 无法确定它何时完成启动并假设它立即启动。
forking
适用于启动后台任务的经典双分叉守护进程或进程。假设当原始进程退出时服务已完成启动。当服务的子进程运行时,该服务被视为正在运行。如果 systemd 猜错了,它可以被告知一个 PID 文件来查找子进程。
我认为你拥有的是 asimple
或 a forking
,但是使用tmux
它会把它搞砸。我认为tmux
会话名义上由守护进程拥有tmux
。因此,systemd 不一定能确定该服务仍在运行并声明其已提前退出。 30 秒的睡眠可能没有帮助,因为它可能会保证您超出forking
或之类的默认启动超时oneshot
。
要解决此问题,您可能需要转换为普通的旧后台任务,&
或者找到某种方法来明确告诉 systemd 哪些进程是您的以及启动何时完成。对于分叉任务,这可能可以通过设置 PID 文件然后使用选项告诉 systemd 在哪里找到它来完成PIDFile=
。另一种选择是创建一个类型为notify
或dbus
的服务,通知 systemd 它们可以直接通过调用启动sd_notify
,也可以通过使用预定义的D-Bus
接口名称来启动。即使如此,我也不确定 tmux 会对此做什么。
答案2
尝试:
Type=oneshot
来自男人:
oneshot 的行为与 simple 类似;但是,服务管理器将在主进程退出后考虑该单元。