Pidfile Management (pid)
The `pid` library (current version 3.0.4) provides robust pidfile management capabilities, including stale detection and file-locking. It can be used as a context manager or a decorator to ensure only one instance of a process is running, and to handle cleanup of the pidfile on termination. It's a stable library with a focus on reliable process control.
Common errors
-
pid.PidFileAlreadyLockedError: Pidfile 'my_app_daemon.pid' already locked by PID 12345
cause Another instance of your application is currently running and successfully acquired the file lock on the pidfile. This is the expected behavior for single-instance applications.fixThis is often not an error but an informative message. If you want to allow multiple instances, the `pid` library might not be suitable or requires custom handling. To stop the existing instance, terminate the process with the reported PID (e.g., `kill 12345`). -
pid.PidFileAlreadyRunningError: Pidfile 'my_app_daemon.pid' already running (pid 12345)
cause A pidfile exists from a previous run (e.g., due to an unclean shutdown), and the PID within that file (12345 in this example) is still active on the system.fixThis usually indicates a stale pidfile or a mismanaged process. Verify if the process with the reported PID is indeed your application. If it's a legitimate active process, handle it as `PidFileAlreadyLockedError`. If it's a stale pidfile, `pid` should ideally clean it up if configured, but manual intervention (deleting the `.pid` file) might be necessary if cleanup failed. -
PermissionError: [Errno 13] Permission denied: '/var/run/my_app_daemon.pid'
cause The user running the application does not have write permissions to the directory where the pidfile is attempted to be created (e.g., `/var/run`). By default, `pid` tries to use system-wide paths.fixSpecify a writable directory for the pidfile using the `piddir` argument, e.g., `PidFile(pidname='my_app_daemon', piddir='/tmp')`. Alternatively, ensure the application is run with sufficient privileges or that the target directory has appropriate permissions. -
ModuleNotFoundError: No module named 'pid'
cause The 'pid' library has not been installed in your current Python environment.fixInstall the library using pip: `pip install pid`.
Warnings
- breaking In version 2.0.0, the behavior of PidFile when used with daemon context managers (like python-daemon) changed. Previously, the process environment (PID) was determined when the PidFile class was instanced, which could lead to incorrect PID determination if a process forked afterward. Now, the environment is determined at the time of acquiring/checking the lock.
- gotcha The `pid` library uses the `atexit` module for pidfile cleanup on termination. However, the default `SIGTERM` handler on some systems might not cleanly exit, preventing `atexit` registered functions from executing. `pid` overrides the default `SIGTERM` handler to ensure cleanup, but this might interact with other custom signal handlers.
- gotcha By default, `PidFile` attempts to acquire a file lock using `fcntl` before checking if a process is running. This means you will typically receive a `PidFileAlreadyLockedError` if another instance holds the lock, rather than `PidFileAlreadyRunningError` which indicates a stale pidfile or an active process with the specified PID.
Install
-
pip install pid
Imports
- PidFile
from pid import PidFile
- pidfile
from pid.decorator import pidfile
Quickstart
import os
import time
from pid import PidFile, PidFileAlreadyLockedError, PidFileAlreadyRunningError
def my_daemon_process():
print("Attempting to start process...")
try:
# By default, creates pidfile in /var/run, or /tmp on some systems.
# pidname defaults to script name.
with PidFile('my_app_daemon') as p:
print(f"Process PID: {os.getpid()} has acquired pidfile {p.path}")
# Simulate daemon work
for i in range(5):
print(f"Working... {i+1}/5")
time.sleep(1)
print("Process finished work and released pidfile.")
except PidFileAlreadyLockedError:
print("Error: Another instance of the process is already running and holds the lock.")
except PidFileAlreadyRunningError:
print("Error: Another instance of the process is already running (pidfile exists and PID is active).")
except Exception as e:
print(f"An unexpected error occurred: {e}")
if __name__ == '__main__':
my_daemon_process()