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, time_out)``
file_name
full path and name of file to use for locking
time_out
how long to wait before concluding that an existing held lock is not
going to be released (default: -1, meaning conclude immediately)
``PidLockFile.acquire(time_out=None)``
''''''''''''''''''''''''''''''''''''''
attempt to capture the lock file; if time_out 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
============
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, time_out)``
file_name
full path and name of file to use for locking
time_out
how long to wait before concluding that an existing held lock is not
going to be released (default: -1, meaning conclude immediately)
``PidLockFile.acquire(time_out=None)``
''''''''''''''''''''''''''''''''''''''
attempt to capture the lock file; if time_out 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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
pandaemonium-0.5.7.zip
(11.5 kB
view details)
pandaemonium-0.5.7.tar.gz
(10.7 kB
view details)
File details
Details for the file pandaemonium-0.5.7.zip
.
File metadata
- Download URL: pandaemonium-0.5.7.zip
- Upload date:
- Size: 11.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | fcce6f7b76b99b23c28ebccabcf3618c94ccb4df5da0a63baec014ba2a1d0f66 |
|
MD5 | 695e4220f4f16996567facabac3be4fe |
|
BLAKE2b-256 | c5677034a8ecff95fe4531f5fc0815ac4aa3adac95719e2ce79c5dca5a6581c3 |
File details
Details for the file pandaemonium-0.5.7.tar.gz
.
File metadata
- Download URL: pandaemonium-0.5.7.tar.gz
- Upload date:
- Size: 10.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | bd99cde22bda465aefc2bdc00ad39e8ac46aa08a294a6375c5ae82797606cf07 |
|
MD5 | 453201fea25f93ef331f6d2b7c0aa144 |
|
BLAKE2b-256 | d3764913dc70e59d9b2e0577a14b85d8b259b53e43f92f0fb5b2ac97db0c95a9 |