Fix deadlock in lazy init: _ensure_initialized calling login via request()
login() called client.request() which called _ensure_initialized() which tried to re-acquire _init_lock — deadlocking forever. Fix: set _initializing=True while inside the init critical section so request() skips the _ensure_initialized() guard when called from within init (safe because query_api_info() already populated the API cache). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -101,6 +101,7 @@ class DsmClient:
|
|||||||
self._reauth_lock = asyncio.Lock()
|
self._reauth_lock = asyncio.Lock()
|
||||||
self._init_lock = asyncio.Lock()
|
self._init_lock = asyncio.Lock()
|
||||||
self._initialized = False
|
self._initialized = False
|
||||||
|
self._initializing = False # True while inside _ensure_initialized
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"DsmClient: base_url=%s verify_ssl=%s timeout=%d",
|
"DsmClient: base_url=%s verify_ssl=%s timeout=%d",
|
||||||
self._base_url,
|
self._base_url,
|
||||||
@@ -131,6 +132,8 @@ class DsmClient:
|
|||||||
async with self._init_lock:
|
async with self._init_lock:
|
||||||
if self._initialized: # re-check inside lock
|
if self._initialized: # re-check inside lock
|
||||||
return
|
return
|
||||||
|
self._initializing = True
|
||||||
|
try:
|
||||||
sys.stderr.write(f"[dsm] Connecting to {self._base_url}...\n")
|
sys.stderr.write(f"[dsm] Connecting to {self._base_url}...\n")
|
||||||
sys.stderr.flush()
|
sys.stderr.flush()
|
||||||
logger.debug("Lazy init: querying API info from %s", self._base_url)
|
logger.debug("Lazy init: querying API info from %s", self._base_url)
|
||||||
@@ -146,6 +149,8 @@ class DsmClient:
|
|||||||
sys.stderr.flush()
|
sys.stderr.flush()
|
||||||
self._initialized = True
|
self._initialized = True
|
||||||
logger.debug("Lazy init complete")
|
logger.debug("Lazy init complete")
|
||||||
|
finally:
|
||||||
|
self._initializing = False
|
||||||
|
|
||||||
async def __aenter__(self) -> DsmClient:
|
async def __aenter__(self) -> DsmClient:
|
||||||
logging.getLogger("httpx").setLevel(logging.WARNING)
|
logging.getLogger("httpx").setLevel(logging.WARNING)
|
||||||
@@ -235,6 +240,9 @@ class DsmClient:
|
|||||||
"""
|
"""
|
||||||
sys.stderr.write(f"[dsm] request: {api}/{method}\n")
|
sys.stderr.write(f"[dsm] request: {api}/{method}\n")
|
||||||
sys.stderr.flush()
|
sys.stderr.flush()
|
||||||
|
# Skip init guard if we are already inside _ensure_initialized (e.g. login call).
|
||||||
|
# The API cache is populated before login, so the cache is ready at this point.
|
||||||
|
if not self._initializing:
|
||||||
await self._ensure_initialized()
|
await self._ensure_initialized()
|
||||||
http = self._get_http()
|
http = self._get_http()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user