Running two tmux sessions as systemd service

I can successfully start/stop a service that creates a tmux session. The service is as following:
test1.service:

[Unit]
Description=First test service

[Service]
Type=forking
User=lancer
ExecStart=/usr/bin/tmux new-session -s test1 -d
ExecStop=/usr/bin/tmux kill-session -t test1

[Install]
WantedBy=multi-user.target

$ sudo systemctl start test1.service
and
$ sudo systemctl stop test1.service

are both successful. Now I would like to have another tmux session that I can control from another service. So I create this test2.service:

    [Unit]
    Description=Second test service
    
    [Service]
    Type=forking
    User=lancer
    ExecStart=/usr/bin/tmux new-session -s test2 -d
    ExecStop=/usr/bin/tmux kill-session -t test2
    
    [Install]
    WantedBy=multi-user.target

Problem: Any of the two works alone. I can see the corresponding tmux session by:
$ tmux ls
If I start the other service, nothing happens. I only have the previous tmux session. Can some one please help?


Solution 1:

Type=forking is not the right type here. It makes systemd expect the tmux process (run from ExecStart=) to fork. But this tmux not always forks.

  • If there is no tmux server, the tmux command will fork. The new tmux process will become a server, it will survive after the original tmux process exits. This is exactly what systemd expects from Type=forking. That's why any of the two services works alone.

  • If there is already a tmux server, the tmux command will communicate with it to create a session; but it won't fork, there is no need to fork. The process will exit without leaving a forked process, still it will report success. My tests indicate that in such situation ExecStop= gets executed. In your case ExecStop= kills the newly created session right away. You don't notice the session is there briefly, you think nothing happens.

One way to deal with the issue is to create a "master" service that starts a tmux server for sure. For it Type=forking is right. You can start a dummy session from it or use start-server (with exit-empty off) and let it run without any session.

Services that create actual sessions should use Type=oneshot with RemainAfterExit=yes, I think. They should want (Wants=) or require (Requires=) the "master" service. I'm not familiar enough with systemd to propose a detailed solution; I'm not even sure if the idea with a "master" service is the best.

Anyway, now you know why in certain circumstances allegedly nothing happens.

Solution 2:

Thanks to @Kamil Maciorowski, I have a solution. Three steps:

  1. Define a master service, master.service, as following:
[Unit]
Description=tmux master service

[Service]
Type=forking
User=lancer
ExecStart=/usr/bin/tmux new-session -s master -d
ExecStop=/usr/bin/tmux kill-session -t master

[Install]
WantedBy=multi-user.target
  1. Define the first service, test1.service, as following:
[Unit]
Description=tmux test 1 service
PartOf=master.service
After=master.service

[Service]
Type=oneshot
RemainAfterExit=yes
User=lancer
ExecStart=/usr/bin/tmux new-session -s test1 -d
ExecStop=/usr/bin/tmux kill-session -t test1

[Install]
WantedBy=multi-user.target
  1. Define the second service, test2.service, as following:
[Unit]
Description=tmux test 2 service
PartOf=master.service
After=master.service

[Service]
Type=oneshot
RemainAfterExit=yes
User=lancer
ExecStart=/usr/bin/tmux new-session -s test2 -d
ExecStop=/usr/bin/tmux kill-session -t test2

[Install]
WantedBy=multi-user.target

Notes:

  1. @Kamil Maciorowski explains why forking and oneshot are used.
  2. The master.service creates a dummy tmux session called master that does nothing but hosts the other actual tmux sessions.
  3. In the test1 and test2 services, After is to make sure at boot-up, the test1 and test2 services start after the master service.
  4. In the test1 and test2 services, PartOf is to make sure that if the master stoped, the test1 and test2 services also stop. Without this, if master stops, test1 and test2 statuses show they are still active.