pidfile handling seems to be really weird in python daemon (or my understanding of its idea is wrong)
It seems to be creating lock (entering pidfile context) in child while I would be expecting it to be created in parent, before fork (and only passed to child to keep it active and to be able to release it on context exit).
Why in parent? To be able to immediately see if it's already locked (in case of trying to start daemon again) before even starting child.
(not working) example, run two in parallel:
import lockfile import daemon import daemon.pidfile import sys import time pidfilename = "/tmp/xx" pidfile = daemon.pidfile.TimeoutPIDLockFile(pidfilename) try: with daemon.DaemonContext(stdout=sys.stdout, stderr=sys.stderr, pidfile=pidfile): time.sleep(60) except lockfile.AlreadyLocked as e: print("daemon is already running") sys.exit(1) else: print("nothing was running earlier")
expected result - getting lockfile.AlreadyLocked in parent actual result - exception is done in child
What's the point of having it in child - no idea. (Almost) every daemon I know acts on pidfile before forking.
On 04-Mar-2025, Arkadiusz Miśkiewicz wrote:
The sequence of steps for a program to become a daemon process, is a matter of long standing convention. Though no formal standard exists, you can read the SystemD manual page ‘daemon(7)’ for a comprehensive description of the procedure to create a so-called “SysV style daemon” that ‘python-daemon’ implements https://www.man7.org/linux/man-pages/man7/daemon.7.html.
What leads you to believe that; do you have a canonical description of the procedure that specifies that?
My sources indicate the convention is to handle creation of the PID file within the actual daemon process (the child process from the ‘fork’ call).
One reason for this is that the PID is not known until the child process exists.
Another is that creation and writing of the PID file is the correct way to avoid a race condition: the file creation is only attempted when we know the child process exists, and creating the PID file is done only to write the PID value into it.
You can see, in the referenced manual page, that the double ‘fork’ (steps 5–7) occur before “In the daemon process, write the daemon PID (as returned by getpid()) to a PID file” (step 12). This is the sequence implemented by ‘python-daemon’.
But the major justification is: This is part of the conventional definition of the “become a daemon process” procedure, and existing daemon implementations now depend on this procedure happening in precisely the specified order.
Thanks for explanation.
Metadata Update from @arekm: - Issue close_status updated to: Invalid - Issue status updated to: Closed (was: Open)