• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

Linux Alternative to while true; do tfs; done

Joined
Dec 7, 2016
Messages
22
Reaction score
6
Does anyone have an alternative to running tfs on ubuntu that isn't a while true loop?

I was thinking about a service maybe using systemd but I couldn't figure out how to make it work, I start the service and it doesn't start. Simple as that.

Anyways, If anyone has an alternative to while true looping the server, I'd appreciate it a lot.

Edit: I'm using Ubuntu 18.04 LTS

Edit 2: Forgot to mention, my server restarts every day because it's a global datapack, I need it to restart everyday at 6 am.
 
Last edited:
Solution
Screen isn't going to help you with that @oen432
It's a neat feature but has nothing to do with using a restarter or service handling.

Using a simple bash loop like while true; do /home/tibia/tfs; sleep 1; done is usually the way most people solve this problem, as you already stated.

Now most services work with PID files and have their own handlers for crashes.
I was thinking about a service maybe using systemd but I couldn't figure out how to make it work, I start the service and it doesn't start. Simple as that.
You are right that systemd is a good way to manage your server.
You also have the option to use init.d. Usually critical services use systemd, like networking or sshd, while not so important...
Screen isn't going to help you with that @oen432
It's a neat feature but has nothing to do with using a restarter or service handling.

Using a simple bash loop like while true; do /home/tibia/tfs; sleep 1; done is usually the way most people solve this problem, as you already stated.

Now most services work with PID files and have their own handlers for crashes.
I was thinking about a service maybe using systemd but I couldn't figure out how to make it work, I start the service and it doesn't start. Simple as that.
You are right that systemd is a good way to manage your server.
You also have the option to use init.d. Usually critical services use systemd, like networking or sshd, while not so important services use init.d, like Nginx or for example nagios or zabbix. In the end systemd is the newer and more reliable system though and there are reasons it was introduced. With its' power, it is also more complicated though.
In the end, whatever you use, is your choice.

Since TFS or any OTS, from my understanding, doesn't use PID files natively, you have a few options.
There are ways to create and delete those using bash, daemons or service handlers.
The other option is to create a watchdog taking care of TFS.

Or when it comes to killing, I wrote a small script (for other purposes though) to kill my application under certain conditions, but it can be used here.
Not tested for TFS, you might have to edit it depending on your exact needs and outputs of ps ax
Bash:
#!/bin/bash
TPID1=$(ps ax | grep tfs | grep -v grep | grep -v "tfs_startscript.sh" | cut -d" " -f1)
TPID2=$(ps ax | grep tfs | grep -v grep | grep -v "tfs_startscript.sh" | cut -d" " -f2)
if [ "$TPID1" = "" ]; then
   kill "$TPID2"
   sleep 5
   kill -9 "$TPID2"
   #echo "$TPID2"
else
   kill "$TPID1"
   sleep 5
   kill -9 "$TPID1"
   #echo "$TPID1"
fi

In the end, I don't really see an issue with using a loop but I would recommend using a service as well for cases like the actual server being restarted.
So I'd just write a bash script with the loop from above, lets call it tfs_startscript.sh
And then create a service starting that script.
Now please remember that the init.d script I show you here is actually pretty old and wasn't 100% reliable.
The systemd script I just wrote and didn't test, so you might have to adjust it a bit.

Bash:
#!/bin/sh
### BEGIN INIT INFO
# Provides:          TFS
# Required-Start:    $local_fs $network $named $time $syslog
# Required-Stop:     $local_fs $network $named $time $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Description:       foo
### END INIT INFO

SCRIPT="/home/tibia/tfs_startscript.sh"
RUNAS=tfs

PIDFILE=/var/run/TFS.pid
LOGFILE=/var/log/TFS.log

start() {
  echo 'Starting service…' >&2
  local CMD="$SCRIPT > \"$LOGFILE\" & echo \$!"
  su -s "/bin/bash" -c "script /dev/null && $CMD" $RUNAS > "$PIDFILE"
  echo 'Service started' >&2
}

stop() {
  echo 'Stopping service…' >&2
  rm -f "$PIDFILE"
  su -s "/bin/bash" -c "script /dev/null && screen -S tfs -X quit" $RUNAS
  echo 'Service stopped' >&2
}

uninstall() {
  echo -n "Are you really sure you want to uninstall this service? That cannot be undone. [yes|No] "
  local SURE
  read SURE
  if [ "$SURE" = "yes" ]; then
    stop
    rm -f "$PIDFILE"
    echo "Notice: log file is not be removed: '$LOGFILE'" >&2
    update-rc.d -f TFS remove
    rm -fv "$0"
  fi
}

case "$1" in
  start)
    start
    ;;
  stop)
    stop
    ;;
  uninstall)
    uninstall
    ;;
  restart)
    stop
    start
    ;;
  *)
    echo "Usage: $0 {start|stop|restart|uninstall}"
esac
Bash:
[Unit]
Description=TFS
After=mysql.service

[Service]
Type=simple
User=tfs
Group=tfs
WorkingDirectory=/home/tibia/
ExecStart=/home/tibia/tfs_startscript.sh
ExecStop=/home/tibia/killtfs.sh
RestartSec=15
Restart=always

[Install]
WantedBy=multi-user.target

Don't forget to enable the service and if needed reload the daemon handling them.
Bash:
sudo chmod +x /etc/init.d/TFS
sudo update-rc.d TFS defaults
sudo update-rc.d TFS enable
sudo systemctl daemon-reload
sudo service TFS start
Bash:
sudo systemctl daemon-reload
sudo systemctl enable tfs.service
sudo systemctl start tfs
sudo systemctl status tfs

I hope I could help you a bit, but you will have to adjust and figure a few things out yourself. Just use google and your brain ;)
 
Last edited:
Solution
As someone who saw "the old days" there is no way to understate just how great systemd unit files are. But if you're not using Linux as a daily driver, I could see how debugging your problem may not be intuitive.

The command sudo systemd status %service.name% should generally tell you something.

But the real meat and potatoes is journald. Behold, the most important command you will learn for modern service management:
sudo journalctl -b -0

This means "show me the entire systemlog for this current session"

You will start at the beginning of the Linux kernel init, and can peruse with pagedown (and pageup) to see every little detail. Found out about problems you may not have known even existed. But more importantly, you can press "End" and jump to the bottom, and see what just happened. And doing that right after you tried to load the unit file you made and tried to run should show you exactly what went wrong. By default it loads in interactive tailing mode, however you can redirect to both grep or tail.

If you're trying to run your unit file over and over, and need to see what happened often, there is two good choices. Keep the tailing mode open in a second session. Or if you prefer just 1 session, pipe the journal to tail after each time you run the unit and it doesn't work:
sudo journalctl -b -0 | tail --lines=20
This will show the last 20 lines of the log.

Alternatives:

However, if you still have issues understanding systemd, a decent alternative is using PM2. Or a custom NodeJS wrapper. Or both. You can even use the NodeJS wrapper to issue signals and arrange fancy timings.

The not-immediately obvious things you will need for PM2 config to run a binary are:
"exec_interpreter": "none",
"exec_mode" : "fork_mode",
"uid": 1234 the numeric user id of the tfs user
"gid": 1234 the numeric group id of the tfs user

The rest you should be able to figure out from the examples and docs. I tend to run PM2 only as root, set a global alias to enforce that, and use uid/gid priv drop for every single last service it manages. its just easier that way
 
+1 on PM2, been using for last 5 years and there isn't anything easier to control and set.
It also generate log files every crash that you can just go to the folder and analyze what happened before (if you're using it with gdb and debugging symbols).
 
Screen isn't going to help you with that @oen432
It's a neat feature but has nothing to do with using a restarter or service handling.

Using a simple bash loop like while true; do /home/tibia/tfs; sleep 1; done is usually the way most people solve this problem, as you already stated.

Now most services work with PID files and have their own handlers for crashes.

You are right that systemd is a good way to manage your server.
You also have the option to use init.d. Usually critical services use systemd, like networking or sshd, while not so important services use init.d, like Nginx or for example nagios or zabbix. In the end systemd is the newer and more reliable system though and there are reasons it was introduced. With its' power, it is also more complicated though.
In the end, whatever you use, is your choice.

Since TFS or any OTS, from my understanding, doesn't use PID files natively, you have a few options.
There are ways to create and delete those using bash, daemons or service handlers.
The other option is to create a watchdog taking care of TFS.

Or when it comes to killing, I wrote a small script (for other purposes though) to kill my application under certain conditions, but it can be used here.
Not tested for TFS, you might have to edit it depending on your exact needs and outputs of ps ax
Bash:
#!/bin/bash
TPID1=$(ps ax | grep tfs | grep -v grep | grep -v "tfs_startscript.sh" | cut -d" " -f1)
TPID2=$(ps ax | grep tfs | grep -v grep | grep -v "tfs_startscript.sh" | cut -d" " -f2)
if [ "$TPID1" = "" ]; then
   kill "$TPID2"
   sleep 5
   kill -9 "$TPID2"
   #echo "$TPID2"
else
   kill "$TPID1"
   sleep 5
   kill -9 "$TPID1"
   #echo "$TPID1"
fi

In the end, I don't really see an issue with using a loop but I would recommend using a service as well for cases like the actual server being restarted.
So I'd just write a bash script with the loop from above, lets call it tfs_startscript.sh
And then create a service starting that script.
Now please remember that the init.d script I show you here is actually pretty old and wasn't 100% reliable.
The systemd script I just wrote and didn't test, so you might have to adjust it a bit.

Bash:
#!/bin/sh
### BEGIN INIT INFO
# Provides:          TFS
# Required-Start:    $local_fs $network $named $time $syslog
# Required-Stop:     $local_fs $network $named $time $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Description:       foo
### END INIT INFO

SCRIPT="/home/tibia/tfs_startscript.sh"
RUNAS=tfs

PIDFILE=/var/run/TFS.pid
LOGFILE=/var/log/TFS.log

start() {
  echo 'Starting service…' >&2
  local CMD="$SCRIPT > \"$LOGFILE\" & echo \$!"
  su -s "/bin/bash" -c "script /dev/null && $CMD" $RUNAS > "$PIDFILE"
  echo 'Service started' >&2
}

stop() {
  echo 'Stopping service…' >&2
  rm -f "$PIDFILE"
  su -s "/bin/bash" -c "script /dev/null && screen -S tfs -X quit" $RUNAS
  echo 'Service stopped' >&2
}

uninstall() {
  echo -n "Are you really sure you want to uninstall this service? That cannot be undone. [yes|No] "
  local SURE
  read SURE
  if [ "$SURE" = "yes" ]; then
    stop
    rm -f "$PIDFILE"
    echo "Notice: log file is not be removed: '$LOGFILE'" >&2
    update-rc.d -f TFS remove
    rm -fv "$0"
  fi
}

case "$1" in
  start)
    start
    ;;
  stop)
    stop
    ;;
  uninstall)
    uninstall
    ;;
  restart)
    stop
    start
    ;;
  *)
    echo "Usage: $0 {start|stop|restart|uninstall}"
esac
Bash:
[Unit]
Description=TFS
After=mysql.service

[Service]
Type=simple
User=tfs
Group=tfs
WorkingDirectory=/home/tibia/
ExecStart=/home/tibia/tfs_startscript.sh
ExecStop=/home/tibia/killtfs.sh
RestartSec=15
Restart=always

[Install]
WantedBy=multi-user.target

Don't forget to enable the service and if needed reload the daemon handling them.
Bash:
sudo chmod +x /etc/init.d/TFS
sudo update-rc.d TFS defaults
sudo update-rc.d TFS enable
sudo systemctl daemon-reload
sudo service TFS start
Bash:
sudo systemctl daemon-reload
sudo systemctl enable tfs.service
sudo systemctl start tfs
sudo systemctl status tfs

I hope I could help you a bit, but you will have to adjust and figure a few things out yourself. Just use google and your brain ;)

This is what I cooked up:
My Systemd service:
Bash:
[Unit]
Description=My Service
After=mysqld.service
StartLimitIntervalSec=0

[Service]
Type=simple
Restart=always
RestartSec=5
User=UserToRunTheProcess #important, don't use root, dunno if your distro complains if running root but mine does

WorkingDirectory=/home/username/otsdirectory
ExecStart=/home/username/otsdirectory/BashScript.sh 

[Install]
WantedBy=multi-user.target
BashScript.sh
Bash:
#!/bin/bash
ulimit -c unlimited
ulimit -n 100000
today=`date '+%Y_%m_%d__%H_%M_%S'`;
while true; do
    ./otbr 2>&1 | tee "log$today.txt";
    echo START SLEEP FOR 2 SECONDS, PRESS CTRL+C TO TURN OFF RESTARTER
    sleep 2
    echo END SLEEP
done

Although I managed to get a restarter for purposes like my vps shutting down for whatever reason, I still have to run the process under a while true...
I also need to create a bash script to close the service properly.

Anyways, just wanted to share my progress, if anyone would like to contribute, feel free to do so.
 
Back
Top