diff --git a/cvat/settings/base.py b/cvat/settings/base.py index 22beff3bcacd..864a15b844ac 100644 --- a/cvat/settings/base.py +++ b/cvat/settings/base.py @@ -15,7 +15,9 @@ https://docs.djangoproject.com/en/2.0/ref/settings/ """ +import fcntl import os +import stat import sys import tempfile import urllib @@ -452,9 +454,49 @@ class REDIS_INMEM_DATABASES(IntEnum): EVENTS_LOCAL_DB_ROOT = BASE_DIR / "events" EVENTS_LOCAL_DB_ROOT.mkdir(parents=True, exist_ok=True) +_events_local_db_slot_lock_fd = None + + +def _resolve_events_local_db_filename(template: str) -> str: + global _events_local_db_slot_lock_fd + + pid = os.getpid() + worker = pid + + if "{worker" in template: + try: + workers = max(1, int(os.getenv("NUMPROCS", "1"))) + except ValueError: + workers = 1 + + slot_locks_root = EVENTS_LOCAL_DB_ROOT / ".slots" + slot_locks_root.mkdir(parents=True, exist_ok=True) + + for slot in range(workers): + lock_file = slot_locks_root / f"worker_{slot:03d}.lock" + fd = os.open(lock_file, os.O_RDWR | os.O_CREAT, stat.S_IRUSR | stat.S_IWUSR) + try: + fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB) + except BlockingIOError: + os.close(fd) + continue + + _events_local_db_slot_lock_fd = fd + worker = slot + break + + try: + return template.format(worker=worker) + except (KeyError, ValueError, IndexError): + return template + + +events_local_db_filename = _resolve_events_local_db_filename( + os.getenv("CVAT_EVENTS_LOCAL_DB_FILENAME", "events.db") +) EVENTS_LOCAL_DB_FILE = Path( EVENTS_LOCAL_DB_ROOT, - os.getenv("CVAT_EVENTS_LOCAL_DB_FILENAME", "events.db"), + events_local_db_filename, ) EVENTS_LOCAL_DB_FILE.touch(exist_ok=True) diff --git a/supervisord/server.conf b/supervisord/server.conf index 1afe17920d83..4872961c83c9 100644 --- a/supervisord/server.conf +++ b/supervisord/server.conf @@ -9,14 +9,14 @@ startretries=5 numprocs=1 process_name=%(program_name)s-%(process_num)d -[fcgi-program:uvicorn] -socket=unix:///tmp/uvicorn.sock +[program:uvicorn] command=%(ENV_HOME)s/wait_for_deps.sh python3 -m uvicorn - --fd 0 + --uds /tmp/uvicorn.sock --forwarded-allow-ips='*' + --workers %(ENV_NUMPROCS)s cvat.asgi:application autorestart=true -environment=CVAT_EVENTS_LOCAL_DB_FILENAME="events_%(process_num)03d.db" -numprocs=%(ENV_NUMPROCS)s +environment=CVAT_EVENTS_LOCAL_DB_FILENAME="events_{worker:03d}.db" +numprocs=1 process_name=%(program_name)s-%(process_num)d