Skip to main content

Framework for writing daemons, with API similar to threading and multiprocessing.

Project description

pandaemonium
============

n. the abode of all the daemons [1]_

pandaemonium provides a framework for writing daemons in Python. The API is
based on the threading/multiprocessing model [2]_ [3]_, so the primary way
of creating your own daemon is to either subclass and override the ``run``
method, or provide a function as the ``target`` to the ``Daemon`` class.

Besides ``Daemon`` there is also a locking pid file -- ``PidLockFile``.
``PidLockFile`` can either be used manually, or, if a complete path and file
name are provided to ``Daemon``, used automatically.


simple usage
------------

from pandaemonium import Daemon

def DoSomethingInteresting():
"Just like it says ;)"
pass

daemon = Daemon(target=DoSomethingInteresting)
daemon.start()
#
# daemon.output will contain any stdout output generated during the
# daemonizing process, up to the stdin/stdout/stderr redirection
#
# daemon.error contains anything sent to the daemon's stderr -- which
# most likely means the daemon died due to an exception
#
# both can be parsed, examined, ignored, etc.


or:

from pandaemonium import Daemon

class MyDaemon(Daemon):
def run():
# do some interesting stuff

md = MyDaemon().start()

The sequence of events that takes place when `start()` is called (adapted from
The Linux Programming Interface by Michael Kerrisk) is:

- detach from the current process, creating a new session
- turn off core dumps
- set uid and gid
- set umask
- set working directory
- create pid file
- set signal handlers
- close inherited file handles
- redirect stdin/stdout/stderr

If any exceptions occur or if any feedback is generated during the `start`
process it will be available as the `error` and `output` attributes of the
daemon instance, where the parent process can analyze, print, etc before
quiting.

Note: Most guides on writing daemons specify setting the umask to 0, but
this creates a security hole as all files become world readable/writable by
default. Pandaemonium sets the umask to 077, but that can be changed if
desired.


advanced usage
--------------

If more control is needed than what is provided by the parameters of Daemon
then one has a couple options available:

- if certain set up / initialization steps need to happen somewhere in the
`start()` sequence, such as after setting the umask and before changing
the working directory::

Daemon.stage4()
# stages 1-4 have now been completed
# do custom steps here
Daemon.start()
# stages 5-9 have now been completed, and run() called

- one can also override any of the stages in a subclass (make sure and
decorate with `check_stage`:

class MyDaemon(Daemon):
def run(self, ip):
# do stuff
@check_stage
def stage7(self):
# do some custom stuff with signals set up

md = MyDaemon('192.168.11.1')
md.start()

- or, to simplify between foreground and daemon operation:

foreground = sys.argv[2:3] == ['--foreground']
pid_file = PidLockFile('/some/path/to/lock.pid')
pid_file.acquire()
if foreground:
pid_file.seal()
else:
daemon = Daemon()
daemon.pid_file = pid_file
daemon.activate()
# at this point, in either foreground or daemon mode, the pid file has
# been sealed (has our correct pid written to it, and it has been
# closed)
run_main_program()

If one's desire is to start the daemon and automatically have any output
printed to screen, one can use `daemon.report()` which prints whatever was
received from the daemon and then quits.


Daemon
------

``Daemon(target=None, args=None, kwargs=None, working_directory='/', umask=0,
prevent_core=True, process_ids=None, inherit_files=None,
signal_map=None, stdin=None, stdout=None, stderr=None)``

target
function to call when daemonized

args
positional args to provide to target

kwargs
keyword args to provide to target

detach
`None` (default) means figure it out, `True` means yes, `False` means no.
Figuring it out means if the parent process is `init`, or a `super
server`, do not detach

working_directory
directory to change to (relative to chroot, if one is in effect)

umask
mask to use when creating files

prevent_core
prevent core dump files from being created

process_ids
tuple of (uid, gid) to switch process to (use (None, None) to disable)

pid_file
`None` (default), or
a PidLockFile instance, or
the string of where to create a PidLockFile

inherit_files
list of open files or file descriptors to keep open

signal_map
dictionary of signal names or numbers to method names or functions

stdin / stdout / stderr
streams to map the standard streams to
default is `None` which is mapped to ``os.devnull``


``Daemon.run()``
''''''''''''''''
Method representing the daemon's activity.

You may override this method in a subclass. The standard ``run``
method invokes the callable object passed to the object's constructor as
the `target` argument, if any, with sequential and keyword arguments taken
from the `args` and `kwargs` arguments, respectively.

``Daemon.start()``
''''''''''''''''''
Start the daemon's activity.

This may be called at most once per daemon object. It arranges for the
object's ``run`` method to be invoked as a daemon process.

``Daemon.monitor()``
''''''''''''''''''''
Collects stdout and stderr from Daemon process until stage 9 and attaches
it to the daemon instance as ``output`` and ``error``. Can be overridden
if one wants to do more interesting stuff with the daemon's output

``Daemon.stage[1-9]()``
''''''''''''''''''''''''''
One can override the various stages for even more customizations options.
Make sure and decorate such functions with ``check_stage``.


PidLockFile
-----------

``PidLockFile(file_name, timeout)``

file_name
full path and name of file to use for locking

timeout
how long to wait before concluding that an existing held lock is not
going to be released (default: -1, meaning conclude immediately)

``PidLockFile.acquire(timeout=None)``
''''''''''''''''''''''''''''''''''''''
attempt to capture the lock file; if timeout is `None` use the time out
specified when PidLockFile was created.

``PidLockFile.seal()``
''''''''''''''''''''''
write the current process' PID into the acquired file and close it --
should only be called by the daemon process or the stored PID will not be
correct.

``PidLockFile.release()``
'''''''''''''''''''''''''
remove the lock file, releasing the lock.



[1] http://dictionary.reference.com/browse/pandemonium
[2] https://docs.python.org/2/library/threading.html#threading.Thread
[3] https://docs.python.org/2/library/multiprocessing.html#multiprocessing.Process


Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pandaemonium-0.8.1.tar.gz (16.0 kB view details)

Uploaded Source

Built Distributions

pandaemonium-0.8.1-py3-none-any.whl (18.0 kB view details)

Uploaded Python 3

pandaemonium-0.8.1-py2-none-any.whl (18.0 kB view details)

Uploaded Python 2

File details

Details for the file pandaemonium-0.8.1.tar.gz.

File metadata

File hashes

Hashes for pandaemonium-0.8.1.tar.gz
Algorithm Hash digest
SHA256 6660e43fa58b2a811c5754a5a7045bce3fee6d83b10b458c4644d9992b9966a6
MD5 46bf8122d1b0a9139f1a925fdb6103d4
BLAKE2b-256 b770b2ad449fc676ed8071d0e8ce5be462b7788a29a21c37e577ddd8bfbcc013

See more details on using hashes here.

File details

Details for the file pandaemonium-0.8.1-py3-none-any.whl.

File metadata

File hashes

Hashes for pandaemonium-0.8.1-py3-none-any.whl
Algorithm Hash digest
SHA256 df356d3b3857ce966b47aa2c650d6a124b6ab4dc26c88c3499fcd5c847966c2f
MD5 9729ab0b5fe4d051e25f1d9a045fbebb
BLAKE2b-256 92415e359dcccceb3f250e27608b56008761949c4c2bf5e8a06c7ca11c5a5adf

See more details on using hashes here.

File details

Details for the file pandaemonium-0.8.1-py2-none-any.whl.

File metadata

File hashes

Hashes for pandaemonium-0.8.1-py2-none-any.whl
Algorithm Hash digest
SHA256 2bdb9d18000a3262056db68e60fc19f47318e2a83d2a9457b5f96417065d5137
MD5 3ca7575e0df6061e16e55c28f62337ff
BLAKE2b-256 df19a82181f8dda9d97d093a73fc3e5a1b453055be0a291339fe0b82ed4ebefa

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page