DEV Community

Cover image for How I Made My Linux Software Keep Running
keonakhon
keonakhon

Posted on • Edited on

How I Made My Linux Software Keep Running

We successfully built our Linux software or package in the previous article. In this article, I'll show you how I made it run on an Ubuntu Server. This can be applied to any Linux OS since they all have the same base.

I will start the package to keep it running by using Systemd, which is at the core of almost all Linux packages. You might be familiar with the command systemctl, which is a part of the Systemd command that we use for starting our database and Nginx. Additionally, we will also update our Python source code. Lastly, we will install our package inside a venv (virtual environment) and make it available outside of the venv.

Systemd Unit File

Create a Systemd unit file named time-tracking-pkg.service, it is a configuration file used by Systemd to define how a service should be managed. Place it into /etc/systemd/system/.

Description=Time Tracking Service
After=syslog.target network.target

[Service]
User=root
ExecStart=/usr/local/bin/time-tracking-pkg
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target
Enter fullscreen mode Exit fullscreen mode

Start Systemd

Run the following commands:

  • Enable the service to start automatically at boot. This is useful for services that need to run continuously.
sudo systemctl enable time-tracking-pkg.service
Enter fullscreen mode Exit fullscreen mode
  • Start our package to keep it running in the background as a daemon or service. Adding its extension is not necessary.
sudo systemctl start time-tracking-pkg.service
Enter fullscreen mode Exit fullscreen mode
  • Check whether it's currently active or not.
sudo systemctl status time-tracking-pkg
Enter fullscreen mode Exit fullscreen mode

Demo: starting service

Now that the service is up and running, in order to track it, I'm going to adjust our Python code and add a socket. Additionally, I will add an argument to make it run only its specified task.

import time
import socket
import argparse


localhost_network = "127.0.0.1"
socket_port = 52000


# Sender Data to socket
def send_data():
    try:
        # Create a socket object
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        # Connect to Receiver
        s.connect((localhost_network, socket_port))

        current_time = time.strftime("%Y-%m-%d %H:%M:%S")

        s.send(current_time.encode())

        # Close the connection
        s.close()
    except Exception:
        pass


# Receive Data from socket
def receive_data():
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        # Set the SO_REUSEADDR option
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

        # Bind and listen
        s.bind((localhost_network, socket_port))
        s.listen()

        # Accept connections
        while True:
            (clientConnected, _) = s.accept()
            try:
                data_from_client = clientConnected.recv(1024)
                data_to_print = data_from_client.decode()
                print(data_to_print)
            finally:
                # Close the connection
                clientConnected.close()
    except socket.error:
        pass
    except KeyboardInterrupt:
        pass
    except Exception:
        pass
    finally:
        s.close()


def main_func():
    try:
        parser = argparse.ArgumentParser(allow_abbrev=False)

        # Define start argument
        parser.add_argument(
            '--start',
            action='store_true',
            help="Use this argument on systemd"
        )

        args = parser.parse_args()

        # Condition when user pass argument start
        if args.start:
            while True:
                send_data()
                time.sleep(5)
        else:
            receive_data()
    except KeyboardInterrupt:
        pass


if __name__ == '__main__':
    main_func()
Enter fullscreen mode Exit fullscreen mode

I used argparse to add an argument named "--start" for calling a function that will initiate sending the datetime data over a socket.

After that, we will compile our project as we did in the previous article. Then, we are going to update our Systemd script to start our service with this argument.
From:

ExecStart=/usr/local/bin/time-tracking-pkg
Enter fullscreen mode Exit fullscreen mode

To be:

ExecStart=/usr/local/bin/time-tracking-pkg --start
Enter fullscreen mode Exit fullscreen mode

After updating, we are going to reload our service with the following commands:

sudo systemctl reenable time-tracking-pkg
sudo systemctl stop time-tracking-pkg
sudo systemctl start time-tracking-pkg
Enter fullscreen mode Exit fullscreen mode

Demo: restart service (1)
or we can also run these commands.

sudo systemctl reenable time-tracking-pkg
sudo systemctl daemon-reload
sudo systemctl restart time-tracking-pkg
Enter fullscreen mode Exit fullscreen mode

Demo: restart service (2)

Now, we can still use time-tracking-pkg command to see the current time.

time-tracking-pkg
Enter fullscreen mode Exit fullscreen mode

Demo: running package along with systemd service

Check The Working Process

Open a new tab to access the server and run the following command.

ps aux | grep time-tracking-pkg
Enter fullscreen mode Exit fullscreen mode

Demo: check working process (1)

You will see two working processes and their Process IDs:

/usr/local/bin/time-tracking-pkg
/usr/local/bin/time-tracking-pkg --start

Systemd service and package diagram

As you can see, even though we didn't run time-tracking-pkg --start, we still see it because Systemd runs it in the background. You can think of it as another program/process.

Now, terminate the tab that is running time-tracking-pkg and then re-run it again; you will notice that its process ID changes. Meanwhile, --start is still running, and its Process ID remains the same.
Demo: check working process (2)

Virtual Environment (venv)

We finally have the service up and running. However, there's a problem with our distribution package setup file. You won't be able to install it on Debian, and in some cases, even further, some of the package versions on the server are incompatible with our package, which would result in errors.

To prevent this from happening, we're going to use a venv. Please ensure that you have python3.XX-venv installed on your Ubuntu Server. If you haven't, please run apt install python3.<enter your python3 version>-venv.

python3 -m venv "time-tracking"
Enter fullscreen mode Exit fullscreen mode

Before activating the venv, I'm going to stop our service and uninstall the package.

systemctl stop time-tracking-pkg
pip3 uninstall -y time-tracking-pkg
Enter fullscreen mode Exit fullscreen mode

The directory named time-tracking will be created at the current directory level where we are currently located. We are going to activate the venv that we just created.

source time-tracking/bin/activate
Enter fullscreen mode Exit fullscreen mode

Demo: installing the package inside venv

Even though we can still run the command normally within the venv, we still need to make the command available outside of the venv. As you can see in the image below, once we exit the venv, we can no longer run the command.
Demo: running the package inside and outside of venv

So, I'm going to create a symlink (symbolic link) or a shortcut of the binary file of our package from inside the venv to /usr/local/bin/.

ln -s /root/time-tracking/bin/time-tracking-pkg /usr/local/bin/time-tracking-pkg
Enter fullscreen mode Exit fullscreen mode

Demo: making a symlink

As you can see, now we can run the command even when we're outside of the venv. However, we still need to start our service again.
Demo: starting a service again and checking the status
Try to run time-tracking-pkg.
Demo: running the command(final)

Finally, we have our service up and running within Systemd and venv. Additionally, You can check the source code in my repository.

Thank you for reading up to this point. Please feel free to leave a comment.



Looking for qualify software with affordable price? contact: funwarn.dev@gmail.com

Top comments (0)