4844cdb7b6
Quite a complex commit by GPT. I'll rewrite it somewhen
36 lines
977 B
Python
36 lines
977 B
Python
from __future__ import annotations
|
||
|
||
import os
|
||
import fcntl
|
||
from typing import Optional
|
||
|
||
_LOCK_FD: Optional[int] = None # keep fd open for process lifetime
|
||
|
||
|
||
def should_start_scheduler() -> bool:
|
||
"""Return True in exactly one process (the scheduler owner).
|
||
|
||
Under gunicorn --workers N, code is imported in N processes. If APScheduler
|
||
starts at import time, you get N schedulers => N× API calls.
|
||
|
||
We prevent that by taking a non-blocking exclusive lock on a lockfile.
|
||
"""
|
||
global _LOCK_FD
|
||
if _LOCK_FD is not None:
|
||
return True
|
||
|
||
lock_path = os.environ.get("LAIR_SCHED_LOCK", "/tmp/lair-scheduler.lock")
|
||
fd = os.open(lock_path, os.O_CREAT | os.O_RDWR, 0o644)
|
||
try:
|
||
fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||
_LOCK_FD = fd
|
||
return True
|
||
except BlockingIOError:
|
||
os.close(fd)
|
||
return False
|
||
except Exception:
|
||
try:
|
||
os.close(fd)
|
||
finally:
|
||
return False
|