Skip to content

Commit f3bead5

Browse files
authored
Merge pull request #45 from knifecake/fix/pidfile-default-none
Align supervisor pidfile behavior with Solid Queue
2 parents 2cb31b7 + 18fa95a commit f3bead5

6 files changed

Lines changed: 62 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
## v0.1.8 - 2026-03-08
6+
7+
**Fixed:**
8+
9+
- Default `steady_queue.supervisor_pidfile` is now `None` (disabled by
10+
default), matching Solid Queue and avoiding stale pidfile issues in
11+
containerized deployments.
12+
- Supervisor pidfiles now register an `atexit` cleanup hook so graceful exits
13+
remove the pidfile more reliably.
14+
315
## v0.1.7 - 2026-02-21
416

517
**Added:**

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -479,8 +479,7 @@ There are several settings that control how Steady Queue works that you can set
479479
requesting immediate termination—defaults to 5 seconds.
480480
- `supervisor_pidfile`: path to a pidfile that the supervisor will create when
481481
booting to prevent running more than one supervisor in the same host, or in
482-
case you want to use it for a health check. It's set to
483-
`tmp/pids/steady_queue_supervisor.pid` by default.
482+
case you want to use it for a health check. It's `None` by default.
484483
- `preserve_finished_jobs`: whether to keep finished jobs in the
485484
`steady_queue_jobs` table—defaults to `True`.
486485
- `clear_finished_jobs_after`: period to keep finished jobs around, in case

docs/configuration.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ Available settings:
189189
``steady_queue.supervisor_pidfile``
190190
Path to a PID file created by the supervisor. Used to prevent multiple
191191
supervisors on the same host and as a health check target. Defaults to
192-
``tmp/pids/steady_queue_supervisor.pid``.
192+
``None``.
193193

194194
``steady_queue.preserve_finished_jobs``
195195
Whether to keep finished jobs in the ``steady_queue_jobs`` table. Defaults

steady_queue/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@
1717

1818
default_concurrency_control_period: timedelta = timedelta(minutes=3)
1919

20-
supervisor_pidfile: Optional[str] = "tmp/pids/steady_queue_supervisor.pid"
20+
supervisor_pidfile: Optional[str] = None
2121

2222
database: str = "default"

steady_queue/processes/pidfile.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import atexit
12
import os
23

34

@@ -9,6 +10,7 @@ def __init__(self, path: str):
910
def setup(self):
1011
self.check_status()
1112
self.write_file()
13+
self.set_at_exit_hook()
1214

1315
def delete(self):
1416
self.delete_file()
@@ -36,6 +38,9 @@ def write_file(self):
3638
self.check_status()
3739
self.write_file()
3840

41+
def set_at_exit_hook(self):
42+
atexit.register(lambda: self.delete() if os.getpid() == self.pid else None)
43+
3944
def delete_file(self):
4045
try:
4146
os.unlink(self.path)

tests/test_pidfile.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import os
2+
from tempfile import TemporaryDirectory
3+
from unittest.mock import patch
4+
5+
from django.test import SimpleTestCase
6+
7+
import steady_queue
8+
from steady_queue.processes.pidfile import Pidfile
9+
10+
11+
class PidfileDefaultsTestCase(SimpleTestCase):
12+
def test_supervisor_pidfile_defaults_to_none(self):
13+
self.assertIsNone(steady_queue.supervisor_pidfile)
14+
15+
16+
class PidfileLifecycleTestCase(SimpleTestCase):
17+
def test_setup_registers_atexit_cleanup_hook(self):
18+
with TemporaryDirectory() as temp_dir, patch("atexit.register") as register:
19+
path = os.path.join(temp_dir, "pids", "steady_queue_supervisor.pid")
20+
21+
pidfile = Pidfile(path)
22+
pidfile.setup()
23+
24+
register.assert_called_once()
25+
self.assertTrue(os.path.exists(path))
26+
with open(path) as f:
27+
self.assertEqual(str(os.getpid()), f.read().strip())
28+
29+
def test_setup_replaces_stale_pidfile_for_dead_process(self):
30+
with TemporaryDirectory() as temp_dir:
31+
path = os.path.join(temp_dir, "pids", "steady_queue_supervisor.pid")
32+
33+
os.makedirs(os.path.dirname(path), exist_ok=True)
34+
with open(path, "w") as f:
35+
f.write("999999")
36+
37+
with patch("atexit.register"):
38+
pidfile = Pidfile(path)
39+
pidfile.setup()
40+
41+
with open(path) as f:
42+
self.assertEqual(str(os.getpid()), f.read().strip())

0 commit comments

Comments
 (0)