Интегрирован wesp в сайт
CI / quality (push) Canceled after 0s

This commit is contained in:
влад
2026-07-17 12:57:18 +03:00
parent 5dfa06ddbe
commit 355c0ef9f1
883 changed files with 194576 additions and 177 deletions
+81
View File
@@ -0,0 +1,81 @@
"""
Межпроцессная блокировка для POST /api/sync/pull по node_id.
threading.Lock в SyncRuntime не действует между процессами (Flask reloader, Gunicorn
workers): два параллельных pull с одним client_id → два process_pull на SQLite и зависание.
На POSIX используем flock на отдельном файле; на Windows — не используем (остаётся thread lock).
"""
from __future__ import annotations
import hashlib
import os
import sys
import tempfile
import time
from pathlib import Path
from typing import BinaryIO, Optional
_HAVE_FCNTL = False
if sys.platform != "win32":
try:
import fcntl # noqa: F401
_HAVE_FCNTL = True
except ImportError:
pass
def ipc_pull_supported() -> bool:
return _HAVE_FCNTL
def _lock_file_path(client_id: str) -> Path:
cid = (client_id or "").strip()
h = hashlib.sha256(cid.encode("utf-8")).hexdigest()[:32]
base = Path(os.getenv("WESP_SYNC_PULL_IPC_LOCK_DIR", tempfile.gettempdir())) / "wesp-sync-pull"
base.mkdir(parents=True, exist_ok=True)
return base / f"{h}.lock"
def ipc_pull_acquire(client_id: str, timeout: float) -> Optional[BinaryIO]:
"""exclusive flock; при таймауте — None. Не вызывать, если не ipc_pull_supported()."""
import fcntl
cid = (client_id or "").strip()
if not cid:
return None
path = _lock_file_path(cid)
fp = open(path, "a+b")
deadline = time.monotonic() + max(0.0, timeout)
try:
while True:
try:
fcntl.flock(fp.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
return fp
except BlockingIOError:
if time.monotonic() >= deadline:
fp.close()
return None
time.sleep(0.05)
except Exception:
try:
fp.close()
except OSError:
pass
raise
def ipc_pull_release(fp: Optional[BinaryIO]) -> None:
if not fp or not _HAVE_FCNTL:
return
import fcntl
try:
fcntl.flock(fp.fileno(), fcntl.LOCK_UN)
except OSError:
pass
try:
fp.close()
except OSError:
pass