bashservicesystemdtmuxreboot

How to get a systemd service running on boot with tmux


I'm trying to have a systemd service run on boot on a raspberry pi. It is a bash script that checks a github repository and keeps a python script running and up to date. I have tried various configurations for the service file noticing that some network errors occurred but I can't seem to have it run as the tmux task doesn't start properly.

[Unit]
Description=Sensor API Service
Wants=network-online.target
After=network.target network-online.target

[Service]
Type=simple
Restart=always
ExecStart=/usr/bin/bash /home/pi/sensor/update.sh

[Install]
WantedBy=network-online.target

After boot tmux doesn't even run properly with the following error:

error connecting to /tmp//tmux-100/default (No such file or directory)

This is the bash script I'm trying to run.

#!/bin/bash

session="sensorInput"
workingDir="/home/pi/sensor"

if [ ! -d $workingDir ]; then
    mkdir $workingDir
    cd $workingDir
else
    cd $workingDir
fi

function UOI () {
    cd $workingDir
    git clone {githublink}
    shopt -s dotglob
    mv -u sensor/* ./
    rm -fr sensor
    git reset --hard
    git pull --force
    git checkout .
    pip3 install -r requirements.txt
}

function run () {
    git fetch
    if [ ! -f "app.py" ]; then
        echo "Python app not found, running update/install function."
        UOI
        echo "Finished installing the script."
        tmux new -d -s $session 'python3 app.py'
        echo "Script is now running in session \'sensorInput\'"
    elif git status --branch --porcelain -uno | grep behind; then
        echo "Differences from main branch found, updating script."
        echo "Terminating python script session."
        tmux kill-session -t $session
        UOI
        echo "Finished updating the script."
        tmux new -d -s $session 'python3 app.py'
        echo "Script is now running in session \'sensorInput\'."
    else
        echo "No differences found, no action taken."
        tmux has-session -t $session 2>/dev/null
        if [ $? != 0 ]; then
            echo "The script is not running, rebooting the script."
            tmux new -d -s $session 'python3 app.py'
            echo "Script is now running in session \'sensorInput\'."
        fi
    fi
}

while true; do run & sleep 60m; done

I have honestly ran out of ideas I searched in quite a bit of other questions and tried modifying the service file but I can't seem to figure it out.

I'm sorry if I somehow missed the question already being answered here before. Hope someone can help me.


Solution

  • After boot tmux doesn't even run properly with the following error: error connecting to /tmp//tmux-100/default (No such file or directory)

    This error indicates that no tmux server is currently running. A tmux server is started automatically the first time you create a new session (via tmux new -s <session name>) or by explicitly starting it with tmux start. I’ve done some limited testing to verify that this is the case at boot with the targets you specify in your service file (though there are caveats to this point).

    You did not post the entire log for this service beyond the one tmux error, but I believe this error is being thrown by either the call to tmux kill-session ... or tmux has-session ... since neither of those commands will start the tmux server and (by inspection) there are certainly logical conditions by which you would call them first when the service starts. And since your call to tmux has-session ... redirects stderr to /dev/null, your error must be coming from the tmux kill command.

    The easiest way to fix this is to explicitly check if tmux is running and start it if it isn’t at the very top of your script. I recommend adding the following to the top of your bash script (update.sh I presume from your service file).

    if [[ ! tmux info &> /dev/null ]]; then
        echo “Starting tmux server”
        tmux start
    fi
    

    Some Additional Comments

    In addition to the above, there are a few things you may want to consider to make this all a little more robust.

    1. I recommend setting a different “WantedBy” target

    The network-online.target is a pretty strange target. As far as I know, this target is usually postponed until the very end of boot (if it is started at all) since it has no dependencies that are tied to the normal boot services, so making it dependent on your service is pretty meaningless. A more reasonable target would be something like multi-user.target.

    2. Consider setting a User= and Group=

    If you put this service file in the systemd path, it would run by root by default. There is also a user service directory that will run services as a specific user, but doing so will only run when that user is logged in I believe. Instead, I recommend adding User= and Group= options to your [Service] section. This will make systemd to run your service as a user. I would recommend it in this case since you are only touching files in a users directory (pi) and do not need root privileges.

    3. Consider setting WorkingDir=home/pi/sensor

    Instead of setting a string in your script and calling cd to it, just set the working directory for the service by setting WorkingDir= in the [Service] section. This will make it so your service starts in the specified directory. No cd necessary. Note, however, that the unit will not create the directory if it doesn’t exist.