Daemoniker provides a cross-platform Python API for running and signaling
daemonized Python code. On Unix, it uses a standard double-fork procedure; on
Windows, it creates an separate subprocess for pythonw.exe
that exists
independently of the initiating process.
Daemoniker also provides several utility tools for the resulting daemons. In particular, it includes cross-platform signaling capability for the created daemons.
Full documentation is available here.
Daemoniker requires Python 3.5 or higher.
pip install daemoniker
Python on Windows ships with pythonw.exe
, which provides a "GUI app with no
GUI" to run Python in the background. But using it precludes ever using the
terminal to exchange information with the process, even to start it. Developers
wanting to create Windows background processes are forced to choose between
writing their own system-tray-minimizable GUI application using pythonw.exe
(or a freezing packager like pyinstaller), or to define and install their code
as a service in the Win32 API. There is a pretty clear gap for a dead-simple
way to "daemonize" running code on Windows, exactly as you would on a Unix
system.
At the beginning of your script, invoke daemonization through the
daemoniker.Daemonizer
context manager:
from daemoniker import Daemonizer
with Daemonizer() as (is_setup, daemonizer):
if is_setup:
# This code is run before daemonization.
do_things_here()
# We need to explicitly pass resources to the daemon; other variables
# may not be correct
is_parent, my_arg1, my_arg2 = daemonizer(
path_to_pid_file,
my_arg1,
my_arg2
)
if is_parent:
# Run code in the parent after daemonization
parent_only_code()
# We are now daemonized, and the parent just exited.
code_continues_here()
Signal handling works through the same path_to_pid_file
:
from daemoniker import SignalHandler1
# Create a signal handler that uses the daemoniker default handlers for
# ``SIGINT``, ``SIGTERM``, and ``SIGABRT``
sighandler = SignalHandler1(path_to_pid_file)
sighandler.start()
# Or, define your own handlers, even after starting signal handling
def handle_sigint(signum):
print('SIGINT received.')
sighandler.sigint = handle_sigint
These processes can then be sent signals from other processes:
from daemoniker import send
from daemoniker import SIGINT
# Send a SIGINT to a process denoted by a PID file
send(path_to_pid_file, SIGINT)
Help is welcome and needed. Unfortunately we're so under-staffed that we haven't even had time to make a thorough contribution guide. In the meantime:
- Issues are great! Open them for anything: feature requests, bug reports, etc.
- Fork, then PR.
- Open an issue for every PR.
- Use the issue for all discussion.
- Reference the PR somewhere in the issue discussion.
- Please be patient. We'll definitely give feedback on anything we bounce back to you, but especially since we lack a contribution guide, style guide, etc, this may be a back-and-forth process.
- Please be courteous in all discussion.
- Contribution guide
- Code of conduct
- Expansion and improvement of test suite
- Clean up and remove unused imports
- Support for privilege dropping
If you like what we're doing, please consider sponsoring or backing Muterra's open source collective.
Sponsors
Backers