Categories
Linux Technology

Run Python Script as System Service in Debian

Recently, I started a Python project that performs some web crawling stuff and presents information via Telegram bot. The project is partially working, hence, I want to make it run on my VPS as a background service. In this post, I will share my configuration to run the Python script using the Linux service manager.

Systemctl is a tool that can control the systemd system and service manager. And systemd is a system and service manager for Linux operating systems. When running as the first process on boot (as PID 1), it acts as init system that brings up and maintains userspace services.

In short, what we need to do is:

Preparing Code and Environment

For this part, you have the full freedom to do anything with your code. Make sure that you have installed all dependencies, and your code can be run without errors. Your script also needs to be capable to handle some system signals like SIGTERM (when you stop a service, the manager will send this signal to your script).

Virtualenv

It is always a good idea to separate your Python environment. I create a separate environment for each project.

# install virtualenv
sudo apt install virtualenv python3-virtualenv

Then, you can create a separated environment. Make sure that you are using the desired python3 or use a full path to a specified Python interpreter. --copies can make your environment fully separated which means it’s portable for other similar machines.

# create your virutal environment
python3 -m venv /path/to/virtual/environment --copies

You can use your environment by commands:

# use your virtualenv
source /path/to/virtual/environment/bin/activate

# exit your virtualenv
deactivate

Signal Handling

To deal with signals in Python, we can use the signal package for Python. Here’s a simple general framework to achieve that:

import signal
# import other stuffs

# the main function
def main():
    # run your script function here
    sth = your_script_class()
    
    # define a signal handler
    def signalHandler(sig, frame):
        print('Signal received: %d' % sig)

        # do something to your running script here
        sth.stop()
        return

    # register your signal handler
    signal.signal(signal.SIGTERM, signalHandler)
    signal.signal(signal.SIGINT, signalHandler)

    # hang the func forever until a signal comes
    # not working on Windows, try to use loops
    signal.pause()
    return

if __name__ == '__main__':
    main()

In the abovementioned codes, we use a closure to handle signals and make the running functions or classes to stop properly. You can modify this framework to adapt to your specific setup.

Service Configuration File

Now, we will do the actual work for the Python script running as a system service. First, create a service file for the systemd (the configuration instruction can be found here):

# you can use any other editor as you wish
# also change the service name
sudo vim /usr/lib/systemd/system/pythonscript.service

Then, add configuration to the file:

[Unit]
Description=Your Service Name
After=multi-user.target

[Service]
Type=idle
Restart=always
RestartSec=30
WorkingDirectory=full/directory/to/your/working/path
ExecStart=/full/directory/to/virtualenv/python /full/directory/to/your/script.py -c command

[Install]
WantedBy=multi-user.target

You need to change the description of your service, working directory and ExecStart (command to start your Python script). Make sure all directories and executables are in full path starting from /. RestartSec specifies a delay in seconds after encountering an exception. If you don’ want your script to restart, you should delete both Restart and RestartSec lines. Service type idle indicates that the service will not be run until all jobs are dispatched.

Reload and Start the Service

Next, we need to reload the newly added service and enable the service on system boot:

# reload
sudo systemctl daemon-reload

# enable
sudo systemctl enable pythonscript.service

Finally, we can run and manage our service using commands:

# run
sudo systemctl start pythonscript.service

# check status
sudo systemctl status pythonscript.service

# stop
sudo systemctl stop pythonscript.service

# restart
sudo systemctl restart pythonscript.service

Note: Some of the status output are omitted. To display the full text output, add -l behind the above commands.

By 533

♥️•🏊•💪🏻 •🐈•📷
•IG: @53333_ @xᴜɴxᴜɴ_ɢʀᴀᴄᴇ
•TW: @SimonNg533

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.