How to make a Python script run like a service or daemon in Linux

Viewed 378997

I have written a Python script that checks a certain e-mail address and passes new e-mails to an external program. How can I get this script to execute 24/7, such as turning it into daemon or service in Linux. Would I also need a loop that never ends in the program, or can it be done by just having the code re executed multiple times?

17 Answers

Assuming that you would really want your loop to run 24/7 as a background service

For a solution that doesn't involve injecting your code with libraries, you can simply create a service template, since you are using linux:

[Unit]
Description = <Your service description here>
After = network.target # Assuming you want to start after network interfaces are made available
 
[Service]
Type = simple
ExecStart = python <Path of the script you want to run>
User = # User to run the script as
Group = # Group to run the script as
Restart = on-failure # Restart when there are errors
SyslogIdentifier = <Name of logs for the service>
RestartSec = 5
TimeoutStartSec = infinity
 
[Install]
WantedBy = multi-user.target # Make it accessible to other users

Place that file in your daemon service folder (usually /etc/systemd/system/), in a *.service file, and install it using the following systemctl commands (will likely require sudo privileges):

systemctl enable <service file name without .service extension>

systemctl daemon-reload

systemctl start <service file name without .service extension>

You can then check that your service is running by using the command:

systemctl | grep running

Ubuntu has a very simple way to manage a service. For python the difference is that ALL the dependencies (packages) have to be in the same directory, where the main file is run from.

I just manage to create such a service to provide weather info to my clients. Steps:

  • Create your python application project as you normally do.

  • Install all dependencies locally like: sudo pip3 install package_name -t .

  • Create your command line variables and handle them in code (if you need any)

  • Create the service file. Something (minimalist) like:

      [Unit]
      Description=1Droid Weather meddleware provider
    
      [Service]
      Restart=always
      User=root
      WorkingDirectory=/home/ubuntu/weather
      ExecStart=/usr/bin/python3 /home/ubuntu/weather/main.py httpport=9570  provider=OWMap
    
      [Install]
      WantedBy=multi-user.target
    
  • Save the file as myweather.service (for example)

  • Make sure that your app runs if started in the current directory

      python3  main.py httpport=9570  provider=OWMap
    
  • The service file produced above and named myweather.service (important to have the extension .service) will be treated by the system as the name of your service. That is the name that you will use to interact with your service.

  • Copy the service file:

      sudo cp myweather.service /lib/systemd/system/myweather.service
    
  • Refresh demon registry:

      sudo systemctl daemon-reload
    
  • Stop the service (if it was running)

      sudo service myweather stop
    
  • Start the service:

      sudo service myweather start
    
  • Check the status (log file with where your print statements go):

      tail -f /var/log/syslog
    
  • Or check the status with:

      sudo service myweather status
    
  • Back to the start with another iteration if needed

This service is now running and even if you log out it will not be affected. And YES if the host is shutdown and restarted this service will be restarted...

You could use Docker for that. The only thing you need then, is to make a script run forever, for example with while True.

  1. The script:
    #!/usr/bin/env python3 
    
    import time
    from datetime import datetime
    
    while True:
        cur_time = datetime.now().isoformat()
        print(f"Hey! I'm still there! The time is: {cur_time}")
        time.sleep(1)
    
  2. Command to run
    docker run \
        -d -it \
        --restart always \
        -v "$(pwd)/script.py:/opt/script.py" \
        --entrypoint=python3 \
        --name my_daemon \
        pycontribs/alpine:latest \
        /opt/script.py
    
    Where:
    • pycontribs/alpine:latest - is an image of a lightweight Linux distro with Python 3.8 preinstalled
    • --name my_daemon - is a clear name for your container
    • --entrypoint=python3 - program to start container with, python3 in the example
    • -v "$(pwd)/script.py:/opt/script.py" - the way to put your script from host inside container to /opt/script.py. Where $(pwd)/script.py - is a path to the script on host system. Better to change it to absolute path, then it would be something like -v "/home/user/Scripts/script.py:/opt/script.py"
    • /opt/script.py - argument to python3 to start with, so in container it would actually be python3 /opt/script.py
    • --restart always - to make the container autostart when the host system starts
  3. Checking the script is running in background:
    $ docker logs my_daemon  -f
    Hey! I'm still there! The time is: 2022-04-20T07:09:11.308271
    Hey! I'm still there! The time is: 2022-04-20T07:09:12.309203
    Hey! I'm still there! The time is: 2022-04-20T07:09:13.310255
    Hey! I'm still there! The time is: 2022-04-20T07:09:14.311309
    Hey! I'm still there! The time is: 2022-04-20T07:09:15.312361
    Hey! I'm still there! The time is: 2022-04-20T07:09:16.313175
    Hey! I'm still there! The time is: 2022-04-20T07:09:17.314242
    Hey! I'm still there! The time is: 2022-04-20T07:09:18.315321
    Hey! I'm still there! The time is: 2022-04-20T07:09:19.315465
    Hey! I'm still there! The time is: 2022-04-20T07:09:20.315807
    Hey! I'm still there! The time is: 2022-04-20T07:09:21.316895
    Hey! I'm still there! The time is: 2022-04-20T07:09:22.317253
    ^C
    

You can run a process as a subprocess inside a script or in another script like this

subprocess.Popen(arguments, close_fds=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL)

Or use a ready-made utility

https://github.com/megashchik/d-handler

Related