Skip to content

pannal/py_daemoniker

 
 

Repository files navigation

What is Daemoniker?

Build Status Build status

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.

Installing

Daemoniker requires Python 3.5 or higher.

    pip install daemoniker

Why daemonization?

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.

Example usage

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)

Contributing

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:

Guide

  • 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.

Project priorities

  • Contribution guide
  • Code of conduct
  • Expansion and improvement of test suite
  • Clean up and remove unused imports
  • Support for privilege dropping

Sponsors and backers

If you like what we're doing, please consider sponsoring or backing Muterra's open source collective.

Sponsors


Backers

About

Cross-platform daemonization tools.

Resources

License

Unlicense, Unlicense licenses found

Licenses found

Unlicense
LICENSE.txt
Unlicense
UNLICENSE.txt

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Python 100.0%