From 2e18e2972376c8a0cc9860dd4b923e38fee060e3 Mon Sep 17 00:00:00 2001 From: HexLab98 Date: Sat, 8 Aug 2026 10:02:47 +0700 Subject: [PATCH] fix(gateway): self-reacquire scoped lock by PID alone After Discord reconnect, on-disk start_time can be null while the live record has a fingerprint. Requiring equality made the gateway treat its own PID as a foreign token holder (#81468). --- gateway/status.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/gateway/status.py b/gateway/status.py index ce02648a958f9..4e6b8c8694567 100644 --- a/gateway/status.py +++ b/gateway/status.py @@ -1391,7 +1391,15 @@ def acquire_scoped_lock(scope: str, identity: str, metadata: Optional[dict[str, except (KeyError, TypeError, ValueError): existing_pid = None - if existing_pid == os.getpid() and existing.get("start_time") == record.get("start_time"): + # Same live PID as this process: always self-reacquire. + # ``start_time`` is a PID-reuse guard for *other* PIDs; it cannot + # distinguish two processes that share the caller's own PID (impossible + # while we are alive). Requiring start_time equality here falsely + # rejects reconnects when the on-disk record has ``start_time: null`` + # (older writers / psutil failure at first write) while the freshly + # built record has a real value — the gateway then reports itself as + # the foreign squatter of its own token (#81468). + if existing_pid == os.getpid(): _write_json_file(lock_path, record) return True, existing @@ -1503,8 +1511,10 @@ def release_scoped_lock(scope: str, identity: str) -> None: return if existing.get("pid") != os.getpid(): return - if existing.get("start_time") != _get_process_start_time(os.getpid()): - return + # Same PID as the live process means we own the lock. Do not require + # start_time equality: on-disk null vs a live fingerprint (macOS/psutil + # timing) would otherwise leave the lock stuck across Discord/Telegram + # reconnects (#81468). start_time only guards PID reuse for *other* PIDs. try: lock_path.unlink(missing_ok=True) except OSError: