Files
ros_control/app/process_lock.py
T

34 lines
1.6 KiB
Python
Raw Normal View History

"""Блокировка файла БД: гарантирует, что с одной файловой БД работает не больше одного процесса
(семафор задач, _sync_lock, кэш бакета и счётчики неудачных паролей — состояние процесса, не БД).
Берётся в lifespan до init_db, снимается при остановке."""
import fcntl
from pathlib import Path
_lock_file = None # открытый дескриптор блокировки текущего процесса (None — не бралась)
def acquire(database_url: str) -> None:
global _lock_file
if not (database_url.startswith("sqlite:///") and ":memory:" not in database_url):
return # :memory: и не-SQLite URL — блокировка не нужна
db_path = Path(database_url.removeprefix("sqlite:///"))
db_path.parent.mkdir(parents=True, exist_ok=True)
lock_path = db_path.with_name(db_path.name + ".lock")
f = open(lock_path, "w")
try:
fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
except OSError:
f.close()
raise RuntimeError(
f"БД {db_path} уже используется другим процессом ros_control: "
"поддерживается только один процесс (--workers 1)"
) from None
_lock_file = f
def release() -> None:
global _lock_file
if _lock_file is not None:
fcntl.flock(_lock_file, fcntl.LOCK_UN)
_lock_file.close()
_lock_file = None