From 3cdc9c119ee9cbf22fcdadd5d9dc8a29838cc810 Mon Sep 17 00:00:00 2001 From: L1nSn0w Date: Sat, 14 Feb 2026 13:03:07 +0800 Subject: [PATCH] refactor(api): enhance DbMigrationAutoRenewLock acquisition logic - Added a check to prevent double acquisition of the DB migration lock, raising an error if an attempt is made to acquire it while already held. - Implemented logic to reuse the lock object if it has already been created, improving efficiency and clarity in lock management. - Reset the lock object to None upon release to ensure proper state management. (cherry picked from commit d4b102d3c8a473c4fd6409dba7c198289bb5f921) --- api/libs/db_migration_lock.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/api/libs/db_migration_lock.py b/api/libs/db_migration_lock.py index 851119c9c0..1d3a81e0a2 100644 --- a/api/libs/db_migration_lock.py +++ b/api/libs/db_migration_lock.py @@ -86,11 +86,17 @@ class DbMigrationAutoRenewLock: Accepts the same args/kwargs as redis-py `Lock.acquire()`. """ - self._lock = self._redis_client.lock( - name=self._name, - timeout=self._ttl_seconds, - thread_local=False, - ) + # Prevent accidental double-acquire which could leave the previous heartbeat thread running. + if self._acquired: + raise RuntimeError("DB migration lock is already acquired; call release_safely() before acquiring again.") + + # Reuse the lock object if we already created one. + if self._lock is None: + self._lock = self._redis_client.lock( + name=self._name, + timeout=self._ttl_seconds, + thread_local=False, + ) acquired = bool(self._lock.acquire(*args, **kwargs)) self._acquired = acquired if acquired: @@ -184,6 +190,7 @@ class DbMigrationAutoRenewLock: ) finally: self._acquired = False + self._lock = None def _stop_heartbeat(self) -> None: if self._stop_event is None: