0

Searched extensively, many questions related but none that I found actually worked.

So I have a shell script which I want to automate via a systemd service. The script:

#!/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

OK this works when run from the shell. Basically it starts the daemon in one window. The daemon inits some stuff, so I have to wait, and after sleeping, I start the second window with the client.

Now when I run as systemd, it actually seems to startup fine, then exits with a failure.

I assume the reason is simple: everything runs through, then the script terminates, so systemd assumes it terminated and exists the service as well - killing the tmux session and windows, which is the real problem.

The goal is to keep the session and windows running forever, unless I run systemctl stop service.

I could just add an endless loop at the end of the script, but that doesn't seem very nice.

Is there a better way? I tried Type=forking but that didn't help either, it also crashed in the end for some reason.

Here is my current systemd script:

[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

I really searched far and wide, if the question/answer already exists, apologies.

2 Answers 2

1

Reading from the documentation:

The trivial service types for systemd are as follows:

oneshot is a service that runs to completion in a short time and then exits completely.

simple is a program that runs in the foreground. As a result systemd cannot determine when it finished starting and assumes it started immediately.

forking is for classic double-forking daemons or processes that start background tasks. It is assumed that the service has finished starting when the original process exits. The service is considered running when it's child processes are running. If systemd guesses this wrong it can be informed of a PID file to look for the child process at.

I think what you have is either a simple or a forking, but using tmux screws it up. I think tmux session are nominally owned by a tmux daemon. As a result systemd can't necessarily figure out that the service is still running and declares it to have exited early. The 30 second sleep probably does not help as it may guarantee you overrun the default startup timeout for something like forking or oneshot.

To fix this you may need to convert to plain old background tasks with & or find some way to explicitly tell systemd which processes are your and when startup is finished. For forking tasks this can probably be done by setting a PID file and then telling systemd where to find it with the PIDFile= option. Another option is to make a service of type notify or dbus which inform systemd they are started either directly with the sd_notify call or by taking a pre-defined D-Bus interface name. Even then I'm not sure what tmux is going to do to that.

0

try:

Type=oneshot

From the man:

Behavior of oneshot is similar to simple; however, the service manager will consider the unit up after the main process exits.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .