From 4a73880ea77a0ecfb203d33f8ea0976c45515db5 Mon Sep 17 00:00:00 2001 From: Klaas van Schelven Date: Mon, 28 Jul 2025 20:46:45 +0200 Subject: [PATCH] PID_FILE check: make optional As implied by this comment: > this implementation is not supposed to be bullet-proof for race conditions (nor is it cross-platform)... it's > just a small check to prevent the regularly occurring cases: > * starting a second runsnappea in development > * running 2 separate instances of bugsink on a single machine without properly distinguishing them but this "small check" gets in the way sometimes, so it's better to be able to turn it off. See #99 --- snappea/foreman.py | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/snappea/foreman.py b/snappea/foreman.py index 6217342..ceb5c59 100644 --- a/snappea/foreman.py +++ b/snappea/foreman.py @@ -103,6 +103,28 @@ class Foreman: logger.info("Startup: Can't run Foreman in TASK_ALWAYS_EAGER mode, EXIT") sys.exit(1) + self.check_pid_file(pid) + + logger.info("Startup: pid is %s", pid) + logger.info("Startup: DB-as-MQ location: %s", settings.DATABASES["snappea"]["NAME"]) + logger.info("Startup: Wake up calls location: %s", self.settings.WAKEUP_CALLS_DIR) + + # Counts the number of "wake up" signals that have not been dealt with yet. The main loop goes to sleep when + # this is 0 + self.signal_semaphore = threading.Semaphore(0) + + # Counts the number of available worker threads. When this is 0, create_workers will first wait until a worker + # stops. (the value of this semaphore is implicitly NUM_WORKERS - active_workers) + self.worker_semaphore = threading.Semaphore(self.settings.NUM_WORKERS) + + def check_pid_file(self, pid): + if self.settings.PID_FILE is None: + # this is useful in setups where the lifecycle of the Foreman is _clearly_ the responsibility of some other + # thing (e.g. systemd), or the whatever is doing container orchestration. In such cases, the PID file is + # only going to get in the way. + logger.warning("Startup: no PID_FILE configured, pid-check disabled") + return + # if the PID_FILE already exists, read it to see whether snappea is already running. # this implementation is not supposed to be bullet-proof for race conditions (nor is it cross-platform)... it's # just a small check to prevent the regularly occurring cases: @@ -126,18 +148,6 @@ class Foreman: with open(self.settings.PID_FILE, "w") as f: f.write(str(pid)) - logger.info("Startup: pid is %s", pid) - logger.info("Startup: DB-as-MQ location: %s", settings.DATABASES["snappea"]["NAME"]) - logger.info("Startup: Wake up calls location: %s", self.settings.WAKEUP_CALLS_DIR) - - # Counts the number of "wake up" signals that have not been dealt with yet. The main loop goes to sleep when - # this is 0 - self.signal_semaphore = threading.Semaphore(0) - - # Counts the number of available worker threads. When this is 0, create_workers will first wait until a worker - # stops. (the value of this semaphore is implicitly NUM_WORKERS - active_workers) - self.worker_semaphore = threading.Semaphore(self.settings.NUM_WORKERS) - def connection_close(self, using="default"): # (as a method to allow for a single point of documentation) @@ -416,4 +426,8 @@ class Foreman: "Stopping: %s did not die in %.1fs, proceeding to kill", short_id(task_id), self.settings.GRACEFUL_TIMEOUT) - os.remove(self.settings.PID_FILE) + if self.settings.PID_FILE is not None: + logger.info("Stopping: removing PID file %s", self.settings.PID_FILE) + os.remove(self.settings.PID_FILE) + else: + logger.info("Stopping: no PID file to remove")