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 SIGTERM
to 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
Difference Between Python'S Generators and Iterators
Find the Similarity Metric Between Two Strings
How to Use CSS Selectors to Retrieve Specific Links Lying in Some Class Using Beautifulsoup
How to Call a Parent Class'S Method from a Child Class in Python
Pandas Column of Lists, Create a Row For Each List Element
Getting a List of All Subdirectories in the Current Directory
How to Crop an Image in Opencv Using Python
Sieve of Eratosthenes - Finding Primes Python
Boolean Operators VS Bitwise Operators
What Does -≫ Mean in Python Function Definitions
Fitting Empirical Distribution to Theoretical Ones With Scipy (Python)
Selecting With Complex Criteria from Pandas.Dataframe
Environment Variables When Script Run by Cron
Schedule Python Script with Crontab
How to Simulate Input to Stdin for Pyunit
How to Install Lxml for Python Without Administative Rights on Linux