How Can Python Handle Systemctl Stop

Stop systemd service running a python program

Systemd sends the SIGTERM to the process - so you need to handle that.

So following little example uses the a signal handler for SIGTERMto clean up a file. Actually it uses atexit to clean up the file, as that handles standard exit conditions as well and a signal handler to initiate in "normal" closing down of the process on receiving the SIGTERM signal

import atexit
import signal
import os

locking_file = "/var/lock/my_service.lock"

if __name__ == '__main__':

def clean_lock():
# atexit handler to clean up a file
os.remove(locking_file)

def signal_term_handler(sigNum, frame):
# on receiving a signal initiate a normal exit
raise SystemExit('terminating')

with open("test_file.lock", "w") as lock:
while True:
lock.write("x")
time.sleep(10)

# register the cleanup handler
atexit.register(clean_lock)
# register the signal handler
signal.signal(signal.SIGTERM, signal_term_handler)

As a note: there is a file locking library you might want to look at:https://pypi.org/project/filelock/ as that should handle that use case as well.

It is not only testing for presents of a file but uses the os-file locking mechanism. I.e. not only the existence of the file is tested - but if it can be locked as well. In effect that means even if the file still exists but the previous process died it is not a problem, as the file is no longer locked.

process management with python: execute service or systemd or init.d script

I found a way using systemd dbus interface. Here is the code:

import dbus
import subprocess
import os
import sys
import time

SYSTEMD_BUSNAME = 'org.freedesktop.systemd1'
SYSTEMD_PATH = '/org/freedesktop/systemd1'
SYSTEMD_MANAGER_INTERFACE = 'org.freedesktop.systemd1.Manager'
SYSTEMD_UNIT_INTERFACE = 'org.freedesktop.systemd1.Unit'

bus = dbus.SystemBus()

proxy = bus.get_object('org.freedesktop.PolicyKit1', '/org/freedesktop/PolicyKit1/Authority')
authority = dbus.Interface(proxy, dbus_interface='org.freedesktop.PolicyKit1.Authority')
system_bus_name = bus.get_unique_name()

subject = ('system-bus-name', {'name' : system_bus_name})
action_id = 'org.freedesktop.systemd1.manage-units'
details = {}
flags = 1 # AllowUserInteraction flag
cancellation_id = '' # No cancellation id

result = authority.CheckAuthorization(subject, action_id, details, flags, cancellation_id)

if result[1] != 0:
sys.exit("Need administrative privilege")

systemd_object = bus.get_object(SYSTEMD_BUSNAME, SYSTEMD_PATH)
systemd_manager = dbus.Interface(systemd_object, SYSTEMD_MANAGER_INTERFACE)

unit = systemd_manager.GetUnit('cups.service')
unit_object = bus.get_object(SYSTEMD_BUSNAME, unit)
#unit_interface = dbus.Interface(unit_object, SYSTEMD_UNIT_INTERFACE)

#unit_interface.Stop('replace')
systemd_manager.StartUnit('cups.service', 'replace')

while list(systemd_manager.ListJobs()):
time.sleep(2)
print 'there are pending jobs, lets wait for them to finish.'

prop_unit = dbus.Interface(unit_object, 'org.freedesktop.DBus.Properties')

active_state = prop_unit.Get('org.freedesktop.systemd1.Unit', 'ActiveState')

sub_state = prop_unit.Get('org.freedesktop.systemd1.Unit', 'SubState')

print active_state, sub_state

Systemd not receiving SIGTERM on stop when using threads in program

Thanks to @Shawn who suggested this old post, I have now solved the problem.

The problem is in how signal handlers are implemented in python. The line t.join() is blocking my main thread and therefore no signals can be received. There are 2 simple solutions:

1) Use python 3.x

or 2) Use signal.pause() to wait for signal like this:

import signal
import time
import threading
import sys

RUN=True

# catch SIGINT and SIGTERM and stop application
def signal_handler(sig, frame):
global RUN
print("Got signal: "+str(sig))
RUN=False
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)

# some working thread inside application
def my_thread():
global RUN
while RUN:
print("sleep")
time.sleep(1.0)

# wait for thread to complete and exit
t = threading.Thread(target=my_thread)
t.start()
signal.pause()
t.join()
print("Done.")

How can I keep my python-daemon process running or restart it on fail?

If you really want to run a script 24/7 in background, the cleanest and easiest way to do it would surely be to create a systemd service.

There are already many descriptions of how to do that, for example here.

One of the advantages of systemd, in addition to being able to launch a service at startup, is to be able to restart it after failure.

Restart=on-failure

If all you want to do is automatically restart the program after a crash, the easiest method would probably be to use a bash script.

You can use the until loop, which is used to execute a given set of commands as long as the given condition evaluates to false.

#!/bin/bash

until python /path/to/script.py; do
echo "The program crashed at `date +%H:%M:%S`. Restarting the script..."
done

If the command returns a non zero exit-status, then the script is restarted.



Related Topics



Leave a reply



Submit