@@ -363,12 +363,14 @@ async def set_state(
363363 # Check that we're holding the lock.
364364 if (
365365 lock_id is not None
366- and await self .redis .get (self ._lock_key (token )) != lock_id
366+ and (existing_lock_id := await self .redis .get (self ._lock_key (token )))
367+ != lock_id
367368 ):
368369 msg = (
369370 f"Lock expired for token { token } while processing. Consider increasing "
370371 f"`app.state_manager.lock_expiration` (currently { self .lock_expiration } ) "
371- "or use `@rx.event(background=True)` decorator for long-running tasks."
372+ "or use `@rx.event(background=True)` decorator for long-running tasks. "
373+ f"Current lock id: { existing_lock_id !r} , expected lock id: { lock_id !r} ."
372374 + (
373375 f" Happened in event: { event .name } "
374376 if (event := context .get ("event" )) is not None
@@ -440,9 +442,10 @@ async def _try_modify_state(
440442 Yields:
441443 The state for the token or None if we couldn't get the lock.
442444 """
445+ event_name = event .name if (event := context .get ("event" )) is not None else None
443446 if not self ._oplock_enabled :
444447 # OpLock is disabled, get a fresh lock, write, and release.
445- async with self ._lock (token ) as lock_id :
448+ async with self ._lock (token , event_name = event_name ) as lock_id :
446449 state = await self .get_state (token )
447450 yield state
448451 await self .set_state (token , state , lock_id = lock_id , ** context )
@@ -459,7 +462,9 @@ async def _try_modify_state(
459462 client_token , _ = _split_substate_key (token )
460463 lock_held_ctx = contextlib .AsyncExitStack ()
461464 try :
462- lock_id = await lock_held_ctx .enter_async_context (self ._lock (token ))
465+ lock_id = await lock_held_ctx .enter_async_context (
466+ self ._lock (token , event_name = event_name )
467+ )
463468 except OplockFound :
464469 # While waiting for the lock, another process has acquired it, but we can piggy back.
465470 pass
@@ -1000,11 +1005,14 @@ async def _wait_lock(self, lock_key: bytes, lock_id: bytes) -> None:
10001005 )
10011006
10021007 @contextlib .asynccontextmanager
1003- async def _lock (self , token : str ):
1008+ async def _lock (
1009+ self , token : str , event_name : str | None = None
1010+ ) -> AsyncIterator [bytes ]:
10041011 """Obtain a redis lock for a token.
10051012
10061013 Args:
10071014 token: The token to obtain a lock for.
1015+ event_name: The name of the event associated with the lock.
10081016
10091017 Yields:
10101018 The ID of the lock (to be passed to set_state).
@@ -1013,7 +1021,9 @@ async def _lock(self, token: str):
10131021 LockExpiredError: If the lock has expired while processing the event.
10141022 """
10151023 lock_key = self ._lock_key (token )
1016- lock_id = uuid .uuid4 ().hex .encode ()
1024+ lock_id = (
1025+ f"{ event_name } _{ uuid .uuid4 ().hex } " if event_name else uuid .uuid4 ().hex
1026+ ).encode ()
10171027
10181028 await self ._wait_lock (lock_key , lock_id )
10191029 state_is_locked = True
0 commit comments