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

pandaemonium provides a framework for writing daemons in Python. The API is based on the threading/multiprocessing model, 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.

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.9.1.tar.gz (17.0 kB view details)

Uploaded Source

Built Distributions

pandaemonium-0.9.1-py3-none-any.whl (14.7 kB view details)

Uploaded Python 3

pandaemonium-0.9.1-py2-none-any.whl (14.7 kB view details)

Uploaded Python 2

File details

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

File metadata

  • Download URL: pandaemonium-0.9.1.tar.gz
  • Upload date:
  • Size: 17.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.3.0 pkginfo/1.7.0 requests/2.25.1 setuptools/58.1.0 requests-toolbelt/0.9.1 tqdm/4.57.0 CPython/3.9.13+

File hashes

Hashes for pandaemonium-0.9.1.tar.gz
Algorithm Hash digest
SHA256 9956966ee469953443ba16582bd36e8fce8e9841a0ced881ecf3c1071ab7b5fa
MD5 09540079f3b5b6218059cdbdbdff6738
BLAKE2b-256 12d51a9c3af5ede8cd55d3c4513a3701a61f5ae0848fc7ded611b9f05895ebb2

See more details on using hashes here.

File details

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

File metadata

  • Download URL: pandaemonium-0.9.1-py3-none-any.whl
  • Upload date:
  • Size: 14.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.3.0 pkginfo/1.7.0 requests/2.25.1 setuptools/58.1.0 requests-toolbelt/0.9.1 tqdm/4.57.0 CPython/3.9.13+

File hashes

Hashes for pandaemonium-0.9.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0db1048ff68f41bbf19c7eb639b6178ec56bd8c8fa44d467c5bf3db258f1f684
MD5 b2479c34d2d6f62dc5c958ece48791e3
BLAKE2b-256 6adc364736c0e3b39213b5bad652b5e071a2ffcd2ac975a5fb3e4ba374ba7243

See more details on using hashes here.

File details

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

File metadata

  • Download URL: pandaemonium-0.9.1-py2-none-any.whl
  • Upload date:
  • Size: 14.7 kB
  • Tags: Python 2
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.3.0 pkginfo/1.7.0 requests/2.25.1 setuptools/58.1.0 requests-toolbelt/0.9.1 tqdm/4.57.0 CPython/3.9.13+

File hashes

Hashes for pandaemonium-0.9.1-py2-none-any.whl
Algorithm Hash digest
SHA256 387b7d083812b05b25818e93e668b963d829ae5ee098abfd9f98ad4b9713e185
MD5 1f5212375050293cbfccb0dc88668515
BLAKE2b-256 79d5c5e7ef29c76586b0fce72bfd344161c4970a314751c2050faa3d818c4fae

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