How I Made My Linux Software Keep Running
Tags: python, linux, tutorial
Published: 2023-10-01 11:50:13

We successfully built our Linux software or package in the [previous article](https://dev.to/keonakhon/how-i-make-my-first-linux-distribution-package-59lj). 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/`.
```systemd
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
```

### Start Systemd
Run the following commands:
- Enable the service to start automatically at boot. This is useful for services that need to run continuously.
```linux
sudo systemctl enable time-tracking-pkg.service
```
- Start our package to keep it running in the background as a daemon or service. Adding its extension is not necessary.
```linux
sudo systemctl start time-tracking-pkg.service
```
- Check whether it's currently active or not.
```linux
sudo systemctl status time-tracking-pkg
```
![Demo: starting service](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mtbpejwyiu71tshy3ub1.png)

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.
```python
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()
```

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](https://dev.to/keonakhon/how-i-make-my-first-linux-distribution-package-59lj). Then, we are going to update our Systemd script to start our service with this argument.
<u>From:</u>
```systemd
ExecStart=/usr/local/bin/time-tracking-pkg
```
<u>To be:</u>
```systemd
ExecStart=/usr/local/bin/time-tracking-pkg --start
```

After updating, we are going to reload our service with the following commands:
```linux
sudo systemctl reenable time-tracking-pkg
sudo systemctl stop time-tracking-pkg
sudo systemctl start time-tracking-pkg
```
![Demo: restart service (1)](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0z3kgv50e60cgwax5u9c.png)
or we can also run these commands.
```linux
sudo systemctl reenable time-tracking-pkg
sudo systemctl daemon-reload
sudo systemctl restart time-tracking-pkg
```
![Demo: restart service (2)](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sa8g2kp09egi6fq3rox6.png)

Now, we can still use `time-tracking-pkg` command to see the current time.
```linux
time-tracking-pkg
```
![Demo: running package along with systemd service](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t33xkhvatpv6l61oqncs.png)

### Check The Working Process
Open a new tab to access the server and run the following command.
```linux
ps aux | grep time-tracking-pkg
```
![Demo: check working process (1)](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l7hu5oqn0mm4r7v7bgfn.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z34vxrjydtrgc40op5vf.png)

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)](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q5h77dhx1p0cvkb088r5.png)

### 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`.
```linux
python3 -m venv "time-tracking"
```
Before activating the venv, I'm going to stop our service and uninstall the package.
```linux
systemctl stop time-tracking-pkg
pip3 uninstall -y time-tracking-pkg
```

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.
```linux
source time-tracking/bin/activate
```
![Demo: installing the package inside venv](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/81ztwtta9kr2hytdaosm.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n7spxd6zhbi7j1jrwewy.png)

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/`.
```linux
ln -s /root/time-tracking/bin/time-tracking-pkg /usr/local/bin/time-tracking-pkg
```
![Demo: making a symlink](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bfo3r05m47rwwhab5yan.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x9emzotgij00gyk3kopw.png)
Try to run `time-tracking-pkg`.
![Demo: running the command(final)](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/06kqq1ap8kgk0ddfx9hz.png)

Finally, we have our service up and running within Systemd and venv. Additionally, You can check the source code in my [repository](https://github.com/keonakhon/time-tracking-package).

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


<br />
<u>Looking for qualify software with affordable price? contact: funwarn.dev@gmail.com</u>