Writing a program to become a well-behaved Unix daemon is somewhatcomplex and tricky to get right, yet the steps are largely similar forany daemon regardless of what else the program may need to do.
This PEP introduces a package to the Python standard library thatprovides a simple interface to the task of becoming a daemon process.
Further exploration of the concepts covered in this PEP has been deferredfor lack of a current champion interested in promoting the goals of the PEPand collecting and incorporating feedback, and with sufficient availabletime to do so effectively.
Simple example of directDaemonContext usage:
importdaemonfromspamimportdo_main_programwithdaemon.DaemonContext():do_main_program()
More complex example usage:
importosimportgrpimportsignalimportdaemonimportlockfilefromspamimport(initial_program_setup,do_main_program,program_cleanup,reload_program_config,)context=daemon.DaemonContext(working_directory='/var/lib/foo',umask=0o002,pidfile=lockfile.FileLock('/var/run/spam.pid'),)context.signal_map={signal.SIGTERM:program_cleanup,signal.SIGHUP:'terminate',signal.SIGUSR1:reload_program_config,}mail_gid=grp.getgrnam('mail').gr_gidcontext.gid=mail_gidimportant_file=open('spam.data','w')interesting_file=open('eggs.data','w')context.files_preserve=[important_file,interesting_file]initial_program_setup()withcontext:do_main_program()
A new package,daemon, is added to the standard library.
A class,DaemonContext, is defined to represent the settings andprocess context for the program running as a daemon process.
DaemonContext objectsADaemonContext instance represents the behaviour settings andprocess context for the program when it becomes a daemon. Thebehaviour and environment is customised by setting options on theinstance, before calling theopen method.
Each option can be passed as a keyword argument to theDaemonContextconstructor, or subsequently altered by assigning to an attribute onthe instance at any time prior to callingopen. That is, foroptions namedwibble andwubble, the following invocation:
foo=daemon.DaemonContext(wibble=bar,wubble=baz)foo.open()
is equivalent to:
foo=daemon.DaemonContext()foo.wibble=barfoo.wubble=bazfoo.open()
The following options are defined.
files_preserveNoneList of files that shouldnot be closed when starting thedaemon. IfNone, all open file descriptors will be closed.
Elements of the list are file descriptors (as returned by a fileobject’sfileno() method) or Pythonfile objects. Eachspecifies a file that is not to be closed during daemon start.
chroot_directoryNoneFull path to a directory to set as the effective root directory ofthe process. IfNone, specifies that the root directory is notto be changed.
working_directory'/'Full path of the working directory to which the process shouldchange on daemon start.
Since a filesystem cannot be unmounted if a process has itscurrent working directory on that filesystem, this should eitherbe left at default or set to a directory that is a sensible “homedirectory” for the daemon while it is running.
umask0File access creation mask (“umask”) to set for the process ondaemon start.
Since a process inherits its umask from its parent process,starting the daemon will reset the umask to this value so thatfiles are created by the daemon with access modes as it expects.
pidfileNoneContext manager for a PID lock file. When the daemon context opensand closes, it enters and exits thepidfile context manager.
detach_processNoneIfTrue, detach the process context when opening the daemoncontext; ifFalse, do not detach.
If unspecified (None) during initialisation of the instance,this will be set toTrue by default, andFalse only ifdetaching the process is determined to be redundant; for example,in the case when the process was started byinit, byinitd, orbyinetd.
signal_mapMapping from operating system signals to callback actions.
The mapping is used when the daemon context opens, and determinesthe action for each signal’s signal handler:
None will ignore the signal (by setting thesignal action tosignal.SIG_IGN).DaemonContext instance. The attribute’s value will be usedas the action for the signal handler.The default value depends on which signals are defined on therunning system. Each item from the list below whose signal isactually defined in thesignal module will appear in thedefault map:
signal.SIGTTIN:Nonesignal.SIGTTOU:Nonesignal.SIGTSTP:Nonesignal.SIGTERM:'terminate'Depending on how the program will interact with its childprocesses, it may need to specify a signal map that includes thesignal.SIGCHLD signal (received when a child process exits).See the specific operating system’s documentation for more detailon how to determine what circumstances dictate the need for signalhandlers.
uidos.getuid()gidos.getgid()The user ID (“UID”) value and group ID (“GID”) value to switchthe process to on daemon start.
The default values, the real UID and GID of the process, willrelinquish any effective privilege elevation inherited by theprocess.
prevent_coreTrueIf true, prevents the generation of core files, in order to avoidleaking sensitive information from daemons run asroot.
stdinNonestdoutNonestderrNoneEach ofstdin,stdout, andstderr is a file-like objectwhich will be used as the new file for the standard I/O streamsys.stdin,sys.stdout, andsys.stderr respectively. The fileshould therefore be open, with a minimum of mode ‘r’ in the caseofstdin, and mode ‘w+’ in the case ofstdout andstderr.
If the object has afileno() method that returns a filedescriptor, the corresponding file will be excluded from beingclosed during daemon start (that is, it will be treated as thoughit were listed infiles_preserve).
IfNone, the corresponding system stream is re-bound to thefile named byos.devnull.
The following methods are defined.
open()NoneOpen the daemon context, turning the current program into a daemonprocess. This performs the following steps:
is_open property is true, returnimmediately. This makes it safe to callopen multiple times onan instance.prevent_core attribute is true, set the resource limitsfor the process to prevent any core dump from the process.chroot_directory attribute is notNone, set theeffective root directory of the process to that directory (viaos.chroot).This allows running the daemon process inside a “chroot gaol”as a means of limiting the system’s exposure to rogue behaviourby the process. Note that the specified directory needs toalready be set up for this purpose.
uid andgid attributevalues.files_preserve attribute, and those that correspond to thestdin,stdout, orstderr attributes.working_directory attribute.umask attribute.detach_process option is true, detach the currentprocess into its own process group, and disassociate from anycontrolling terminal.signal_map attribute.stdin,stdout,stderr are notNone, bind the system streamssys.stdin,sys.stdout,and/orsys.stderr to the files represented by thecorresponding attributes. Where the attribute has a filedescriptor, the descriptor is duplicated (instead of re-bindingthe name).pidfile attribute is notNone, enter its contextmanager.open andclose calls).close method to be called during Python’s exitprocessing.When the function returns, the running program is a daemonprocess.
close()NoneClose the daemon context. This performs the following steps:
is_open property is false, returnimmediately. This makes it safe to callclose multiple timeson an instance.pidfile attribute is notNone, exit its contextmanager.openandclose calls).is_openTrue if the instance is open,False otherwise.This property exposes the state indicating whether the instance iscurrently open. It isTrue if the instance’sopen method hasbeen called and theclose method has not subsequently beencalled.
terminate(signal_number,stack_frame)NoneSignal handler for thesignal.SIGTERM signal. Performs thefollowing step:
SystemExit exception explaining the signal.The class also implements the context manager protocol via__enter__ and__exit__ methods.
__enter__()DaemonContext instanceCall the instance’sopen() method, then return the instance.
__exit__(exc_type,exc_value,exc_traceback)True orFalse as defined by the context managerprotocolCall the instance’sclose() method, then returnTrue if theexception was handled orFalse if it was not.
The majority of programs written to be Unix daemons either implementbehaviour very similar to that in thespecification, or arepoorly-behaved daemons by thecorrect daemon behaviour.
Since these steps should be much the same in most implementations butare very particular and easy to omit or implement incorrectly, theyare a prime target for a standard well-tested implementation in thestandard library.
According to Stevens in[stevens] §2.6, a program should perform thefollowing steps to become a Unix daemon process.
init process.SIGTERM signal.SIGCLD signal.Thedaemon tool[slack-daemon] lists (in its summary of features)behaviour that should be performed when turning a program into awell-behaved Unix daemon process. It differs from this PEP’s intent inthat it invokes aseparate program as a daemon process. Thefollowing features are appropriate for a daemon that starts itselfonce the program is already running:
initd(8) orinetd(8).This PEP addresses only Unix-style daemons, for which the abovecorrect behaviour is relevant, as opposed to comparable behaviours onother operating systems.
There is a related concept in many systems, called a “service”. Aservice differs from the model in this PEP, in that rather than havingthecurrent program continue to run as a daemon process, a servicestarts anadditional process to run in the background, and thecurrent process communicates with that additional process via somedefined channels.
The Unix-style daemon model in this PEP can be used, among otherthings, to implement the background-process part of a service; butthis PEP does not address the other aspects of setting up and managinga service.
Thepython-daemon package[python-daemon].
Prior to this PEP, several existing third-party Python libraries ortools implemented some of this PEP’scorrect daemon behaviour.
Thereference implementation is a fairly direct successor from thefollowing implementations:
bda.daemon library[bda.daemon] is an implementation of[cookbook-66012]. It is the predecessor of[python-daemon].Other Python daemon implementations that differ from this PEP:
zdaemon tool[zdaemon] was written for the Zope project. Like[slack-daemon], it differs from this specification because it isused to run another program as a daemon process.daemon[clapper-daemon] is (according to itshomepage) no longer maintained. As of version 1.0.1, it implementsthe basic steps from[stevens].daemonize library[seutter-daemonize] also implements thebasic steps from[stevens].daemon.py module[burr-daemon] provides the[stevens]procedure as well as PID file handling and redirection of output tosyslog.initd library[dagitses-initd], which uses[clapper-daemon], implements an equivalent of Unixinitd(8) forcontrolling a daemon process.daemon toolhttp://www.libslack.org/daemon/ by “raf” <raf@raf.org>.python-daemon libraryhttp://pypi.python.org/pypi/python-daemon/ by Ben Finney etal.bda.daemon libraryhttp://pypi.python.org/pypi/bda.daemon/ by RobertNiederreiter et al.zdaemon toolhttp://pypi.python.org/pypi/zdaemon/ byGuido van Rossum et al.daemon libraryhttp://pypi.python.org/pypi/daemon/ byBrian Clapper.daemonize libraryhttp://daemonize.sourceforge.net/ byJerry Seutter.daemon.py modulehttp://www.nightmare.com/~ryb/code/daemon.py by Ray Burr.Twisted application frameworkhttp://pypi.python.org/pypi/Twisted/ by Glyph Lefkowitz etal.initd libraryhttp://pypi.python.org/pypi/initd/by Michael Andreas Dagitses.This work is hereby placed in the public domain. To the extent thatplacing a work in the public domain is not legally possible, thecopyright holder hereby grants to all recipients of this work allrights and freedoms that would otherwise be restricted by copyright.
Source:https://github.com/python/peps/blob/main/peps/pep-3143.rst
Last modified:2025-02-01 08:59:27 GMT