MCPcopy Create free account
hub / github.com/dot-agent/nextpy / StateProxy

Class StateProxy

nextpy/backend/state.py:1296–1447  ·  view source on GitHub ↗

Proxy of a state instance to control mutability of vars for a background task. Since a background task runs against a state instance without holding the state_manager lock for the token, the reference may become stale if the same state is modified by another event handler. The prox

Source from the content-addressed store, hash-verified

1294
1295
1296class StateProxy(wrapt.ObjectProxy):
1297 """Proxy of a state instance to control mutability of vars for a background task.
1298
1299 Since a background task runs against a state instance without holding the
1300 state_manager lock for the token, the reference may become stale if the same
1301 state is modified by another event handler.
1302
1303 The proxy object ensures that writes to the state are blocked unless
1304 explicitly entering a context which refreshes the state from state_manager
1305 and holds the lock for the token until exiting the context. After exiting
1306 the context, a StateUpdate may be emitted to the frontend to notify the
1307 client of the state change.
1308
1309 A background task will be passed the `StateProxy` as `self`, so mutability
1310 can be safely performed inside an `async with self` block.
1311
1312 class State(xt.State):
1313 counter: int = 0
1314
1315 @xt.background
1316 async def bg_increment(self):
1317 await asyncio.sleep(1)
1318 async with self:
1319 self.counter += 1
1320 """
1321
1322 def __init__(self, state_instance):
1323 """Create a proxy for a state instance.
1324
1325 Args:
1326 state_instance: The state instance to proxy.
1327 """
1328 super().__init__(state_instance)
1329 # compile is not relevant to backend logic
1330 #TODO: We're currently using this weirdo mechanism for installing initial packages
1331 # gets to load_module -> compile -> get_frontend_packages -> install_frontend_packages
1332 # We can improve this
1333 self._self_app = getattr(prerequisites.get_app(), constants.CompileVars.APP)
1334 self._self_substate_path = state_instance.get_full_name().split(".")
1335 self._self_actx = None
1336 self._self_mutable = False
1337
1338 async def __aenter__(self) -> StateProxy:
1339 """Enter the async context manager protocol.
1340
1341 Sets mutability to True and enters the `App.modify_state` async context,
1342 which refreshes the state from state_manager and holds the lock for the
1343 given state token until exiting the context.
1344
1345 Background tasks should avoid blocking calls while inside the context.
1346
1347 Returns:
1348 This StateProxy instance in mutable mode.
1349 """
1350 self._self_actx = self._self_app.modify_state(
1351 self.__wrapped__.router.session.client_token
1352 )
1353 mutable_state = await self._self_actx.__aenter__()

Callers 2

test_state_proxyFunction · 0.90
_get_event_handlerMethod · 0.85

Calls

no outgoing calls

Tested by 1

test_state_proxyFunction · 0.72