commandnet 0.6.0__tar.gz → 0.6.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: commandnet
3
- Version: 0.6.0
3
+ Version: 0.6.1
4
4
  Summary: A lightweight, Pydantic-powered, distributed event-driven state machine and typed node graph runtime.
5
5
  Author: Christopher Vaz
6
6
  Author-email: christophervaz160@gmail.com
@@ -106,22 +106,15 @@ class Engine:
106
106
  if hasattr(ctx, "is_cancelled"):
107
107
  ctx.is_cancelled = await self.db.is_cancelled(subject_id)
108
108
 
109
- # 2. RELEASE LOCK before long-running compute
110
- await self.db.unlock_subject(subject_id)
111
-
112
- # 3. COMPUTE (no DB lock held)
109
+ # 2. COMPUTE (Lock is HELD via Redis during compute)
113
110
  start_t = asyncio.get_event_loop().time()
114
- result = await node_cls().run(ctx, payload)
111
+ try:
112
+ result = await node_cls().run(ctx, payload)
113
+ except asyncio.CancelledError:
114
+ self.logger.warning(f"Task {subject_id} cancelled during compute. Emitting Interrupt.")
115
+ result = Interrupt(subject_id=subject_id, hard=True)
116
+
115
117
  duration = (asyncio.get_event_loop().time() - start_t) * 1000
116
-
117
- # 4. RE-LOCK before writing
118
- node_name_check, _ = await self.db.lock_and_load(subject_id)
119
-
120
- # 🔴 IMPORTANT SAFETY CHECK (prevents stale writes)
121
- if node_name_check != event.node_name and node_name_check != "AWAITING_CALL":
122
- await self.db.unlock_subject(subject_id)
123
- return
124
-
125
118
  await self._apply_target(subject_id, ctx, result, duration)
126
119
 
127
120
  except Exception as e:
@@ -264,6 +257,22 @@ class Engine:
264
257
  subject_id, join_name, len(target.branches)
265
258
  )
266
259
 
260
+ async def _run_branch(task: ParallelTask):
261
+ branch_payload = (
262
+ task.payload if task.payload is not None else payload
263
+ )
264
+
265
+ sub_ctx = self._get_path(context, task.sub_context_path)
266
+
267
+ await self._apply_target(
268
+ f"{subject_id}#{task.sub_context_path}",
269
+ sub_ctx,
270
+ task.action,
271
+ payload=branch_payload,
272
+ )
273
+
274
+ branch_tasks = []
275
+
267
276
  for branch in target.branches:
268
277
  # Normalize branch into ParallelTask
269
278
  if isinstance(branch, ParallelTask):
@@ -276,19 +285,10 @@ class Engine:
276
285
  )
277
286
  task = ParallelTask(action=branch, sub_context_path=path)
278
287
 
279
- # PROPAGATION: fallback to incoming payload if branch has none
280
- branch_payload = (
281
- task.payload if task.payload is not None else payload
282
- )
283
-
284
- sub_ctx = self._get_path(context, task.sub_context_path)
288
+ branch_tasks.append(asyncio.create_task(_run_branch(task)))
285
289
 
286
- await self._apply_target(
287
- f"{subject_id}#{task.sub_context_path}",
288
- sub_ctx,
289
- task.action,
290
- payload=branch_payload,
291
- )
290
+ if branch_tasks:
291
+ await asyncio.gather(*branch_tasks)
292
292
 
293
293
  if target.join_node:
294
294
  await self.db.save_state(
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "commandnet"
3
- version = "0.6.0"
3
+ version = "0.6.1"
4
4
  description = "A lightweight, Pydantic-powered, distributed event-driven state machine and typed node graph runtime."
5
5
  authors = [
6
6
  { name = "Christopher Vaz", email = "christophervaz160@gmail.com" }
File without changes