digitalkin 0.3.1.dev0__py3-none-any.whl → 0.3.1.dev1__py3-none-any.whl

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.
digitalkin/__version__.py CHANGED
@@ -5,4 +5,4 @@ from importlib.metadata import PackageNotFoundError, version
5
5
  try:
6
6
  __version__ = version("digitalkin")
7
7
  except PackageNotFoundError:
8
- __version__ = "0.3.1.dev0"
8
+ __version__ = "0.3.1.dev1"
@@ -140,7 +140,7 @@ class TaskiqJobManager(BaseJobManager[InputModelT, OutputModelT, SetupModelT]):
140
140
  services_mode: ServicesMode,
141
141
  default_timeout: float = 10.0,
142
142
  max_concurrent_tasks: int = 100,
143
- stream_timeout: float = 15.0,
143
+ stream_timeout: float = 30.0,
144
144
  ) -> None:
145
145
  """Initialize the Taskiq job manager.
146
146
 
@@ -298,7 +298,6 @@ class TaskiqJobManager(BaseJobManager[InputModelT, OutputModelT, SetupModelT]):
298
298
  while True:
299
299
  try:
300
300
  # Block for first item with timeout to allow termination checks
301
- # Configurable timeout (default 15s) to account for distributed system latencies
302
301
  item = await asyncio.wait_for(queue.get(), timeout=self.stream_timeout)
303
302
  queue.task_done()
304
303
  yield item
@@ -11,6 +11,7 @@ from typing import Any
11
11
  from digitalkin.core.task_manager.surrealdb_repository import SurrealDBConnection
12
12
  from digitalkin.core.task_manager.task_session import TaskSession
13
13
  from digitalkin.logger import logger
14
+ from digitalkin.models.core.task_monitor import CancellationReason
14
15
  from digitalkin.modules._base_module import BaseModule
15
16
 
16
17
 
@@ -84,13 +85,32 @@ class BaseTaskManager(ABC):
84
85
  task_id: The ID of the task to clean up
85
86
  mission_id: The ID of the mission associated with the task
86
87
  """
88
+ session = self.tasks_sessions.get(task_id)
89
+ cancellation_reason = session.cancellation_reason.value if session else "no_session"
90
+ final_status = session.status.value if session else "unknown"
91
+
87
92
  logger.debug(
88
- "Cleaning up resources for task: '%s'", task_id, extra={"mission_id": mission_id, "task_id": task_id}
93
+ "Cleaning up resources",
94
+ extra={
95
+ "mission_id": mission_id,
96
+ "task_id": task_id,
97
+ "final_status": final_status,
98
+ "cancellation_reason": cancellation_reason,
99
+ },
89
100
  )
90
- if task_id in self.tasks_sessions:
91
- session = self.tasks_sessions[task_id]
101
+
102
+ if session:
92
103
  await session.cleanup()
93
104
  self.tasks_sessions.pop(task_id, None)
105
+ logger.debug(
106
+ "Task session cleanup completed",
107
+ extra={
108
+ "mission_id": mission_id,
109
+ "task_id": task_id,
110
+ "final_status": final_status,
111
+ "cancellation_reason": cancellation_reason,
112
+ },
113
+ )
94
114
 
95
115
  self.tasks.pop(task_id, None)
96
116
 
@@ -261,10 +281,21 @@ class BaseTaskManager(ABC):
261
281
  )
262
282
 
263
283
  except asyncio.TimeoutError:
284
+ # Set timeout as cancellation reason
285
+ if task_id in self.tasks_sessions:
286
+ session = self.tasks_sessions[task_id]
287
+ if session.cancellation_reason == CancellationReason.UNKNOWN:
288
+ session.cancellation_reason = CancellationReason.TIMEOUT
289
+
264
290
  logger.warning(
265
291
  "Graceful cancellation timed out for task: '%s', forcing cancellation",
266
292
  task_id,
267
- extra={"mission_id": mission_id, "task_id": task_id, "timeout": timeout},
293
+ extra={
294
+ "mission_id": mission_id,
295
+ "task_id": task_id,
296
+ "timeout": timeout,
297
+ "cancellation_reason": CancellationReason.TIMEOUT.value,
298
+ },
268
299
  )
269
300
 
270
301
  # Phase 2: Force cancellation
@@ -272,8 +303,16 @@ class BaseTaskManager(ABC):
272
303
  with contextlib.suppress(asyncio.CancelledError):
273
304
  await task
274
305
 
275
- logger.warning("Task force-cancelled: '%s'", task_id, extra={"mission_id": mission_id, "task_id": task_id})
276
- await self._cleanup_task(task_id, mission_id)
306
+ logger.warning(
307
+ "Task force-cancelled: '%s', reason: %s",
308
+ task_id,
309
+ CancellationReason.TIMEOUT.value,
310
+ extra={
311
+ "mission_id": mission_id,
312
+ "task_id": task_id,
313
+ "cancellation_reason": CancellationReason.TIMEOUT.value,
314
+ },
315
+ )
277
316
  return True
278
317
 
279
318
  except Exception as e:
@@ -283,10 +322,9 @@ class BaseTaskManager(ABC):
283
322
  extra={"mission_id": mission_id, "task_id": task_id, "error": str(e)},
284
323
  exc_info=True,
285
324
  )
286
- await self._cleanup_task(task_id, mission_id)
287
325
  return False
288
-
289
- await self._cleanup_task(task_id, mission_id)
326
+ finally:
327
+ await self._cleanup_task(task_id, mission_id)
290
328
  return True
291
329
 
292
330
  async def clean_session(self, task_id: str, mission_id: str) -> bool:
@@ -382,7 +420,16 @@ class BaseTaskManager(ABC):
382
420
  results: dict[str, bool | BaseException] = {}
383
421
  for task_id, result in zip(task_ids, results_list):
384
422
  if isinstance(result, Exception):
385
- logger.error("Exception cancelling task %s: %s", task_id, result)
423
+ logger.error(
424
+ "Exception cancelling task: '%s', error: %s",
425
+ task_id,
426
+ result,
427
+ extra={
428
+ "mission_id": mission_id,
429
+ "task_id": task_id,
430
+ "error": str(result),
431
+ },
432
+ )
386
433
  results[task_id] = False
387
434
  else:
388
435
  results[task_id] = result
@@ -403,6 +450,21 @@ class BaseTaskManager(ABC):
403
450
  )
404
451
 
405
452
  self._shutdown_event.set()
453
+
454
+ # Mark all sessions with shutdown reason before cancellation
455
+ for task_id, session in self.tasks_sessions.items():
456
+ if session.cancellation_reason == CancellationReason.UNKNOWN:
457
+ session.cancellation_reason = CancellationReason.SHUTDOWN
458
+ logger.debug(
459
+ "Marking task for shutdown: '%s'",
460
+ task_id,
461
+ extra={
462
+ "mission_id": mission_id,
463
+ "task_id": task_id,
464
+ "cancellation_reason": CancellationReason.SHUTDOWN.value,
465
+ },
466
+ )
467
+
406
468
  results = await self.cancel_all_tasks(mission_id, timeout)
407
469
 
408
470
  failed_tasks = [task_id for task_id, success in results.items() if not success]
@@ -411,13 +473,26 @@ class BaseTaskManager(ABC):
411
473
  "Failed to cancel %d tasks during shutdown: %s",
412
474
  len(failed_tasks),
413
475
  failed_tasks,
414
- extra={"mission_id": mission_id, "failed_tasks": failed_tasks, "failed_count": len(failed_tasks)},
476
+ extra={
477
+ "mission_id": mission_id,
478
+ "failed_tasks": failed_tasks,
479
+ "failed_count": len(failed_tasks),
480
+ "cancellation_reason": CancellationReason.SHUTDOWN.value,
481
+ },
415
482
  )
416
483
 
417
484
  # Clean up any remaining sessions (in case cancellation didn't clean them)
418
485
  remaining_sessions = list(self.tasks_sessions.keys())
419
486
  if remaining_sessions:
420
- logger.info("Cleaning up %d remaining task sessions", len(remaining_sessions))
487
+ logger.info(
488
+ "Cleaning up %d remaining task sessions after shutdown",
489
+ len(remaining_sessions),
490
+ extra={
491
+ "mission_id": mission_id,
492
+ "remaining_sessions": remaining_sessions,
493
+ "remaining_count": len(remaining_sessions),
494
+ },
495
+ )
421
496
  cleanup_coros = [self._cleanup_task(task_id, mission_id) for task_id in remaining_sessions]
422
497
  await asyncio.gather(*cleanup_coros, return_exceptions=True)
423
498
 
@@ -8,7 +8,12 @@ from typing import Any
8
8
  from digitalkin.core.task_manager.surrealdb_repository import SurrealDBConnection
9
9
  from digitalkin.core.task_manager.task_session import TaskSession
10
10
  from digitalkin.logger import logger
11
- from digitalkin.models.core.task_monitor import SignalMessage, SignalType, TaskStatus
11
+ from digitalkin.models.core.task_monitor import (
12
+ CancellationReason,
13
+ SignalMessage,
14
+ SignalType,
15
+ TaskStatus,
16
+ )
12
17
 
13
18
 
14
19
  class TaskExecutor:
@@ -82,7 +87,7 @@ class TaskExecutor:
82
87
  finally:
83
88
  logger.info("Heartbeat task ended", extra={"mission_id": mission_id, "task_id": task_id})
84
89
 
85
- async def supervisor() -> None:
90
+ async def supervisor() -> None: # noqa: C901, PLR0912, PLR0915
86
91
  """Supervise the three concurrent tasks and handle outcomes.
87
92
 
88
93
  Raises:
@@ -96,6 +101,7 @@ class TaskExecutor:
96
101
  main_task = None
97
102
  hb_task = None
98
103
  sig_task = None
104
+ cleanup_reason = CancellationReason.UNKNOWN
99
105
 
100
106
  try:
101
107
  main_task = asyncio.create_task(coro, name=f"{task_id}_main")
@@ -106,12 +112,37 @@ class TaskExecutor:
106
112
  return_when=asyncio.FIRST_COMPLETED,
107
113
  )
108
114
 
109
- # One task completed -> cancel the others
110
- for t in pending:
111
- t.cancel()
115
+ # Determine cleanup reason based on which task completed first
116
+ completed = next(iter(done))
117
+
118
+ if completed is main_task:
119
+ # Main task finished - cleanup is due to success
120
+ cleanup_reason = CancellationReason.SUCCESS_CLEANUP
121
+ elif completed is sig_task or (completed is hb_task and sig_task.done()):
122
+ # Signal task finished - external cancellation
123
+ cleanup_reason = CancellationReason.SIGNAL
124
+ elif completed is hb_task:
125
+ # Heartbeat stopped - failure cleanup
126
+ cleanup_reason = CancellationReason.FAILURE_CLEANUP
127
+
128
+ # Cancel pending tasks with proper reason logging
129
+ if pending:
130
+ pending_names = [t.get_name() for t in pending]
131
+ logger.debug(
132
+ "Cancelling pending tasks: %s, reason: %s",
133
+ pending_names,
134
+ cleanup_reason.value,
135
+ extra={
136
+ "mission_id": mission_id,
137
+ "task_id": task_id,
138
+ "pending_tasks": pending_names,
139
+ "cancellation_reason": cleanup_reason.value,
140
+ },
141
+ )
142
+ for t in pending:
143
+ t.cancel()
112
144
 
113
145
  # Propagate exception/result from the finished task
114
- completed = next(iter(done))
115
146
  await completed
116
147
 
117
148
  # Determine final status based on which task completed
@@ -122,50 +153,95 @@ class TaskExecutor:
122
153
  extra={"mission_id": mission_id, "task_id": task_id},
123
154
  )
124
155
  elif completed is sig_task or (completed is hb_task and sig_task.done()):
125
- logger.debug(
126
- f"Task cancelled due to signal {sig_task=}",
127
- extra={"mission_id": mission_id, "task_id": task_id},
128
- )
129
156
  session.status = TaskStatus.CANCELLED
157
+ session.cancellation_reason = CancellationReason.SIGNAL
158
+ logger.info(
159
+ "Task cancelled via external signal",
160
+ extra={
161
+ "mission_id": mission_id,
162
+ "task_id": task_id,
163
+ "cancellation_reason": CancellationReason.SIGNAL.value,
164
+ },
165
+ )
130
166
  elif completed is hb_task:
131
167
  session.status = TaskStatus.FAILED
168
+ session.cancellation_reason = CancellationReason.HEARTBEAT_FAILURE
132
169
  logger.error(
133
- f"Heartbeat stopped for {task_id}",
134
- extra={"mission_id": mission_id, "task_id": task_id},
170
+ "Heartbeat stopped unexpectedly for task: '%s'",
171
+ task_id,
172
+ extra={
173
+ "mission_id": mission_id,
174
+ "task_id": task_id,
175
+ "cancellation_reason": CancellationReason.HEARTBEAT_FAILURE.value,
176
+ },
135
177
  )
136
178
  msg = f"Heartbeat stopped for {task_id}"
137
179
  raise RuntimeError(msg) # noqa: TRY301
138
180
 
139
181
  except asyncio.CancelledError:
140
182
  session.status = TaskStatus.CANCELLED
141
- logger.info("Task cancelled", extra={"mission_id": mission_id, "task_id": task_id})
183
+ # Only set reason if not already set (preserve original reason)
184
+ logger.info(
185
+ "Task cancelled externally: '%s', reason: %s",
186
+ task_id,
187
+ session.cancellation_reason.value,
188
+ extra={
189
+ "mission_id": mission_id,
190
+ "task_id": task_id,
191
+ "cancellation_reason": session.cancellation_reason.value,
192
+ },
193
+ )
194
+ cleanup_reason = CancellationReason.FAILURE_CLEANUP
142
195
  raise
143
196
  except Exception:
144
197
  session.status = TaskStatus.FAILED
145
- logger.exception("Task failed", extra={"mission_id": mission_id, "task_id": task_id})
198
+ cleanup_reason = CancellationReason.FAILURE_CLEANUP
199
+ logger.exception(
200
+ "Task failed with exception: '%s'",
201
+ task_id,
202
+ extra={"mission_id": mission_id, "task_id": task_id},
203
+ )
146
204
  raise
147
205
  finally:
148
206
  session.completed_at = datetime.datetime.now(datetime.timezone.utc)
149
- # Ensure all tasks are cleaned up
150
- tasks_to_cleanup = [t for t in [main_task, hb_task, sig_task] if t is not None]
151
- for t in tasks_to_cleanup:
152
- if not t.done():
153
- t.cancel()
207
+ # Ensure all tasks are cleaned up with proper reason
208
+ tasks_to_cleanup = [t for t in [main_task, hb_task, sig_task] if t is not None and not t.done()]
154
209
  if tasks_to_cleanup:
210
+ cleanup_names = [t.get_name() for t in tasks_to_cleanup]
211
+ logger.debug(
212
+ "Final cleanup of %d remaining tasks: %s, reason: %s",
213
+ len(tasks_to_cleanup),
214
+ cleanup_names,
215
+ cleanup_reason.value,
216
+ extra={
217
+ "mission_id": mission_id,
218
+ "task_id": task_id,
219
+ "cleanup_count": len(tasks_to_cleanup),
220
+ "cleanup_tasks": cleanup_names,
221
+ "cancellation_reason": cleanup_reason.value,
222
+ },
223
+ )
224
+ for t in tasks_to_cleanup:
225
+ t.cancel()
155
226
  await asyncio.gather(*tasks_to_cleanup, return_exceptions=True)
156
227
 
228
+ duration = (
229
+ (session.completed_at - session.started_at).total_seconds()
230
+ if session.started_at and session.completed_at
231
+ else None
232
+ )
157
233
  logger.info(
158
- "Task execution completed with status: %s",
159
- session.status,
234
+ "Task execution completed: '%s', status: %s, reason: %s, duration: %.2fs",
235
+ task_id,
236
+ session.status.value,
237
+ session.cancellation_reason.value if session.status == TaskStatus.CANCELLED else "n/a",
238
+ duration or 0,
160
239
  extra={
161
240
  "mission_id": mission_id,
162
241
  "task_id": task_id,
163
- "status": session.status,
164
- "duration": (
165
- (session.completed_at - session.started_at).total_seconds()
166
- if session.started_at and session.completed_at
167
- else None
168
- ),
242
+ "status": session.status.value,
243
+ "cancellation_reason": session.cancellation_reason.value,
244
+ "duration": duration,
169
245
  },
170
246
  )
171
247
 
@@ -6,7 +6,13 @@ from collections.abc import AsyncGenerator
6
6
 
7
7
  from digitalkin.core.task_manager.surrealdb_repository import SurrealDBConnection
8
8
  from digitalkin.logger import logger
9
- from digitalkin.models.core.task_monitor import HeartbeatMessage, SignalMessage, SignalType, TaskStatus
9
+ from digitalkin.models.core.task_monitor import (
10
+ CancellationReason,
11
+ HeartbeatMessage,
12
+ SignalMessage,
13
+ SignalType,
14
+ TaskStatus,
15
+ )
10
16
  from digitalkin.modules._base_module import BaseModule
11
17
 
12
18
 
@@ -31,6 +37,7 @@ class TaskSession:
31
37
  completed_at: datetime.datetime | None
32
38
 
33
39
  is_cancelled: asyncio.Event
40
+ cancellation_reason: CancellationReason
34
41
  _paused: asyncio.Event
35
42
  _heartbeat_interval: datetime.timedelta
36
43
  _last_heartbeat: datetime.datetime
@@ -62,6 +69,7 @@ class TaskSession:
62
69
  self.heartbeat_record_id = None
63
70
 
64
71
  self.is_cancelled = asyncio.Event()
72
+ self.cancellation_reason = CancellationReason.UNKNOWN
65
73
  self._paused = asyncio.Event()
66
74
  self._heartbeat_interval = heartbeat_interval
67
75
 
@@ -143,17 +151,26 @@ class TaskSession:
143
151
 
144
152
  async def generate_heartbeats(self) -> None:
145
153
  """Periodic heartbeat generator with cancellation support."""
146
- logger.debug("Heartbeat started")
154
+ logger.debug(
155
+ "Heartbeat generator started for task: '%s'",
156
+ self.task_id,
157
+ extra={"task_id": self.task_id, "mission_id": self.mission_id},
158
+ )
147
159
  while not self.cancelled:
148
- logger.debug(f"Heartbeat tick for task: '{self.task_id}' | {self.cancelled=}")
160
+ logger.debug(
161
+ "Heartbeat tick for task: '%s', cancelled=%s",
162
+ self.task_id,
163
+ self.cancelled,
164
+ extra={"task_id": self.task_id, "mission_id": self.mission_id},
165
+ )
149
166
  success = await self.send_heartbeat()
150
167
  if not success:
151
168
  logger.error(
152
169
  "Heartbeat failed, cancelling task: '%s'",
153
170
  self.task_id,
154
- extra={"task_id": self.task_id},
171
+ extra={"task_id": self.task_id, "mission_id": self.mission_id},
155
172
  )
156
- await self._handle_cancel()
173
+ await self._handle_cancel(CancellationReason.HEARTBEAT_FAILURE)
157
174
  break
158
175
  await asyncio.sleep(self._heartbeat_interval.total_seconds())
159
176
 
@@ -192,7 +209,7 @@ class TaskSession:
192
209
  continue
193
210
 
194
211
  if signal["action"] == "cancel":
195
- await self._handle_cancel()
212
+ await self._handle_cancel(CancellationReason.SIGNAL)
196
213
  elif signal["action"] == "pause":
197
214
  await self._handle_pause()
198
215
  elif signal["action"] == "resume":
@@ -222,26 +239,55 @@ class TaskSession:
222
239
  extra={"task_id": self.task_id},
223
240
  )
224
241
 
225
- async def _handle_cancel(self) -> None:
226
- """Idempotent cancellation with acknowledgment."""
227
- logger.debug("Handle cancel called")
242
+ async def _handle_cancel(self, reason: CancellationReason = CancellationReason.UNKNOWN) -> None:
243
+ """Idempotent cancellation with acknowledgment and reason tracking.
244
+
245
+ Args:
246
+ reason: The reason for cancellation (signal, heartbeat failure, cleanup, etc.)
247
+ """
228
248
  if self.is_cancelled.is_set():
229
249
  logger.debug(
230
- "Cancel signal ignored - task already cancelled: '%s'",
250
+ "Cancel ignored - task already cancelled: '%s' (existing reason: %s, new reason: %s)",
231
251
  self.task_id,
232
- extra={"task_id": self.task_id},
252
+ self.cancellation_reason.value,
253
+ reason.value,
254
+ extra={
255
+ "task_id": self.task_id,
256
+ "mission_id": self.mission_id,
257
+ "existing_reason": self.cancellation_reason.value,
258
+ "new_reason": reason.value,
259
+ },
233
260
  )
234
261
  return
235
262
 
236
- logger.info(
237
- "Cancelling task: '%s'",
238
- self.task_id,
239
- extra={"task_id": self.task_id},
240
- )
241
-
263
+ self.cancellation_reason = reason
242
264
  self.status = TaskStatus.CANCELLED
243
265
  self.is_cancelled.set()
244
266
 
267
+ # Log with appropriate level based on reason
268
+ if reason in {CancellationReason.SUCCESS_CLEANUP, CancellationReason.FAILURE_CLEANUP}:
269
+ logger.debug(
270
+ "Task cancelled (cleanup): '%s', reason: %s",
271
+ self.task_id,
272
+ reason.value,
273
+ extra={
274
+ "task_id": self.task_id,
275
+ "mission_id": self.mission_id,
276
+ "cancellation_reason": reason.value,
277
+ },
278
+ )
279
+ else:
280
+ logger.info(
281
+ "Task cancelled: '%s', reason: %s",
282
+ self.task_id,
283
+ reason.value,
284
+ extra={
285
+ "task_id": self.task_id,
286
+ "mission_id": self.mission_id,
287
+ "cancellation_reason": reason.value,
288
+ },
289
+ )
290
+
245
291
  # Resume if paused so cancellation can proceed
246
292
  if self._paused.is_set():
247
293
  self._paused.set()
@@ -220,9 +220,13 @@ class ModuleServicer(module_service_pb2_grpc.ModuleServiceServicer, ArgParser):
220
220
  break
221
221
 
222
222
  if message.get("code", None) is not None and message.get("code") == "__END_OF_STREAM__":
223
- yield lifecycle_pb2.StartModuleResponse(success=True, job_id=job_id)
223
+ logger.info(
224
+ "End of stream via __END_OF_STREAM__",
225
+ extra={"job_id": job_id, "mission_id": request.mission_id},
226
+ )
224
227
  break
225
228
 
229
+ logger.info("Yielding message from job %s: %s", job_id, message)
226
230
  proto = json_format.ParseDict(message, struct_pb2.Struct(), ignore_unknown_fields=True)
227
231
  yield lifecycle_pb2.StartModuleResponse(success=True, output=proto, job_id=job_id)
228
232
  finally:
@@ -17,6 +17,23 @@ class TaskStatus(Enum):
17
17
  FAILED = "failed"
18
18
 
19
19
 
20
+ class CancellationReason(Enum):
21
+ """Reason for task cancellation - helps distinguish cleanup vs real cancellation."""
22
+
23
+ # Cleanup cancellations (not errors)
24
+ SUCCESS_CLEANUP = "success_cleanup" # Main task completed, cleaning up helper tasks
25
+ FAILURE_CLEANUP = "failure_cleanup" # Main task failed, cleaning up helper tasks
26
+
27
+ # Real cancellations
28
+ SIGNAL = "signal" # External signal requested cancellation
29
+ HEARTBEAT_FAILURE = "heartbeat_failure" # Heartbeat stopped working
30
+ TIMEOUT = "timeout" # Task timed out
31
+ SHUTDOWN = "shutdown" # Manager is shutting down
32
+
33
+ # Unknown/unset
34
+ UNKNOWN = "unknown" # Reason not determined
35
+
36
+
20
37
  class SignalType(Enum):
21
38
  """Signal type enumeration."""
22
39
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: digitalkin
3
- Version: 0.3.1.dev0
3
+ Version: 0.3.1.dev1
4
4
  Summary: SDK to build kin used in DigitalKin
5
5
  Author-email: "DigitalKin.ai" <contact@digitalkin.ai>
6
6
  License: Attribution-NonCommercial-ShareAlike 4.0 International
@@ -452,7 +452,7 @@ Classifier: License :: Other/Proprietary License
452
452
  Requires-Python: >=3.10
453
453
  Description-Content-Type: text/markdown
454
454
  License-File: LICENSE
455
- Requires-Dist: digitalkin-proto>=0.2.0.dev4
455
+ Requires-Dist: digitalkin-proto==0.2.0.dev4
456
456
  Requires-Dist: grpcio-health-checking>=1.76.0
457
457
  Requires-Dist: grpcio-reflection>=1.76.0
458
458
  Requires-Dist: grpcio-status>=1.76.0
@@ -460,7 +460,7 @@ Requires-Dist: pydantic>=2.12.4
460
460
  Requires-Dist: surrealdb>=1.0.6
461
461
  Provides-Extra: taskiq
462
462
  Requires-Dist: rstream>=0.40.0; extra == "taskiq"
463
- Requires-Dist: taskiq-aio-pika>=0.4.4; extra == "taskiq"
463
+ Requires-Dist: taskiq-aio-pika>=0.5.0; extra == "taskiq"
464
464
  Requires-Dist: taskiq-redis>=1.1.2; extra == "taskiq"
465
465
  Requires-Dist: taskiq[reload]>=0.11.20; extra == "taskiq"
466
466
  Dynamic: license-file
@@ -7,7 +7,7 @@ base_server/mock/__init__.py,sha256=YZFT-F1l_TpvJYuIPX-7kTeE1CfOjhx9YmNRXVoi-jQ,
7
7
  base_server/mock/mock_pb2.py,sha256=sETakcS3PAAm4E-hTCV1jIVaQTPEAIoVVHupB8Z_k7Y,1843
8
8
  base_server/mock/mock_pb2_grpc.py,sha256=BbOT70H6q3laKgkHfOx1QdfmCS_HxCY4wCOX84YAdG4,3180
9
9
  digitalkin/__init__.py,sha256=7LLBAba0th-3SGqcpqFO-lopWdUkVLKzLZiMtB-mW3M,162
10
- digitalkin/__version__.py,sha256=Q0IBkIes3oz9LCKqzDtGa5rK6FC1xTmf-s6rHrrfiuQ,195
10
+ digitalkin/__version__.py,sha256=IXDN38pf9GYznzUOcCygvxQc4p61JPJp3xDMpPowM8o,195
11
11
  digitalkin/logger.py,sha256=8ze_tjt2G6mDTuQcsf7-UTXWP3UHZ7LZVSs_iqF4rX4,4685
12
12
  digitalkin/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  digitalkin/core/__init__.py,sha256=FJRcJ-B1Viyn-38L8XpOpZ8KOnf1I7PCDOAmKXLQhqc,71
@@ -17,18 +17,18 @@ digitalkin/core/job_manager/__init__.py,sha256=gGtgQpE6vbBHxAj1SYMbcpj45Q6x8Icsq
17
17
  digitalkin/core/job_manager/base_job_manager.py,sha256=yVaakJNIEPWc6ND1bWrUgBA-8r1yEEQZ_iNP1RnK0jY,10076
18
18
  digitalkin/core/job_manager/single_job_manager.py,sha256=7MkttI7pP0aZUHgz8apQf3kXHNI3Mbh8F5LfKwLhRpo,13789
19
19
  digitalkin/core/job_manager/taskiq_broker.py,sha256=4BbuvKZNWIVbAHmle8XdpPolHhiOv9XgCWR1VGAFg8E,11400
20
- digitalkin/core/job_manager/taskiq_job_manager.py,sha256=04DDMhik09368aCGxmrqR011VOEDgmpFVxC_ugN6Fzs,21352
20
+ digitalkin/core/job_manager/taskiq_job_manager.py,sha256=IQ2g34mA_AsbIHNiSpzxxT6KzoOEUVb_67659LgBT_4,21251
21
21
  digitalkin/core/task_manager/__init__.py,sha256=k9i-qIoee_1yXogyQolaVFDUQBIZU3ENbYKtjrCNmTQ,31
22
- digitalkin/core/task_manager/base_task_manager.py,sha256=CCAltJul85WMVEaJMsNHO58QSIirRrOcVZj7cQud-v8,16751
22
+ digitalkin/core/task_manager/base_task_manager.py,sha256=ahkflSul07hMAWRX22CoJf9FxpQhWzi_oKZz3YAN6lc,19416
23
23
  digitalkin/core/task_manager/local_task_manager.py,sha256=Z1gv4dCGD32LBSfMZJ4dGyYDe80lZRAyowTgGC6E4Vk,3534
24
24
  digitalkin/core/task_manager/remote_task_manager.py,sha256=zgccmnwwtB0nyeIZlL5Ji8SY1J89z_vjA4JD9ur7HzY,3082
25
25
  digitalkin/core/task_manager/surrealdb_repository.py,sha256=eNOVrYhTiIM0jd8j46fsKDr_THbGdK3xrog2jeqSQyA,9671
26
- digitalkin/core/task_manager/task_executor.py,sha256=EN8aIXZFh01dMcMw01u5QEKw3mz1IAkIWpe4l3zssc0,7373
27
- digitalkin/core/task_manager/task_session.py,sha256=OT0jV_xYCAEyB3krSaGMqHUiGEOinu2h7Y-3kIu3Zx8,11525
26
+ digitalkin/core/task_manager/task_executor.py,sha256=8xh5_1zuRAaGZIH_gWyNsA4T7YYaF0sl51dLS8a6aAk,10981
27
+ digitalkin/core/task_manager/task_session.py,sha256=0p8jPsPhtD0TgBNaE4AdU_0QLLHERhD5s2eV5HBLbU0,13307
28
28
  digitalkin/grpc_servers/__init__.py,sha256=ZIRMJ1Lcas8yQ106GCup6hn2UBOsx1sNk8ap0lpEDnY,72
29
29
  digitalkin/grpc_servers/_base_server.py,sha256=ZVeCDwI7w7fFbPTXPkeJb_SOuLfd2T7za3T4oCu2UWY,18680
30
30
  digitalkin/grpc_servers/module_server.py,sha256=fJncoCQ-nHK4rs1PFM99Ds0U1Axjxj1X4ILeud96AvM,10235
31
- digitalkin/grpc_servers/module_servicer.py,sha256=JxZwoMNi1nkMOW7qCQrvV5fJd5y-PWU-bq-EAgwtLHc,19404
31
+ digitalkin/grpc_servers/module_servicer.py,sha256=8enBRV5EArfZ9g4ak9fIC4PDk4IRNoHm4e3_B-Mx6VI,19614
32
32
  digitalkin/grpc_servers/registry_server.py,sha256=v4pFpkcnWHL3Sm4CHw8wTKbSAvppEYgg_ikgdirmazc,2235
33
33
  digitalkin/grpc_servers/registry_servicer.py,sha256=5AaGacM875fHCiOmMRuqx4Q3ZsR5yvdfjuRsV4xhRcA,16485
34
34
  digitalkin/grpc_servers/utils/__init__.py,sha256=ZnAIb_F8z4NhtPypqkdmzgRSzolKnJTk3oZx5GfWH5Y,38
@@ -47,7 +47,7 @@ digitalkin/mixins/storage_mixin.py,sha256=ptZ4a2bydIa48q0V9e395vWHTu7yw4A6rI4jwK
47
47
  digitalkin/models/__init__.py,sha256=hDHtUfswaNh8wo4NZaBItg9JqC0uNSRqXArNWSrGynY,163
48
48
  digitalkin/models/core/__init__.py,sha256=jOMDmPX0uSfGA9zUi0u_kOvYJ46VdIssoIhVYvNSeew,19
49
49
  digitalkin/models/core/job_manager_models.py,sha256=RCrW20HCTQ7l2D1JtNgEKefZpMzoN-uAXK8bPorIqqA,1120
50
- digitalkin/models/core/task_monitor.py,sha256=JBMzqaKLrsxb0QZYM1BlvCxxkbqD_YKgsWob7bsmBeE,1626
50
+ digitalkin/models/core/task_monitor.py,sha256=XNYCxhN9QqJZhuO2LoiWEHZwhA35dsupyfYvek_pgE8,2295
51
51
  digitalkin/models/grpc_servers/__init__.py,sha256=0tA71nPSXgRrh9DoLvx-TSwZXdYIRUEItoadpTL1cTo,42
52
52
  digitalkin/models/grpc_servers/models.py,sha256=ZQ1Gk4zmLRX_ueuwFOwXgtyG9OEPSzFa_91I_CXZmZ0,8957
53
53
  digitalkin/models/grpc_servers/types.py,sha256=rQ78s4nAet2jy-NIDj_PUWriT0kuGHr_w6ELjmjgBao,539
@@ -104,14 +104,14 @@ digitalkin/utils/arg_parser.py,sha256=wzscRlE1Qp1gGl-lAJlkkwnbU1O2oezj6BwK_BZFBI
104
104
  digitalkin/utils/development_mode_action.py,sha256=2hznh0ajW_4ZTysfoc0Y49161f_PQPATRgNk8NAn1_o,1623
105
105
  digitalkin/utils/llm_ready_schema.py,sha256=JjMug_lrQllqFoanaC091VgOqwAd-_YzcpqFlS7p778,2375
106
106
  digitalkin/utils/package_discover.py,sha256=sa6Zp5Kape1Zr4iYiNrnZxiHDnqM06ODk6yfWHom53w,13465
107
- digitalkin-0.3.1.dev0.dist-info/licenses/LICENSE,sha256=Ies4HFv2r2hzDRakJYxk3Y60uDFLiG-orIgeTpstnIo,20327
107
+ digitalkin-0.3.1.dev1.dist-info/licenses/LICENSE,sha256=Ies4HFv2r2hzDRakJYxk3Y60uDFLiG-orIgeTpstnIo,20327
108
108
  modules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
109
109
  modules/cpu_intensive_module.py,sha256=ejB9XPnFfA0uCuFUQbM3fy5UYfqqAlF36rv_P5Ri8ho,8363
110
110
  modules/minimal_llm_module.py,sha256=Ijld__ZnhzfLwpXD1XVkLZ7jyKZKyOFZczOpiPttJZc,11216
111
111
  modules/text_transform_module.py,sha256=bwPSnEUthZQyfLwcTLo52iAxItAoknkLh8Y3m5aywaY,7251
112
112
  services/filesystem_module.py,sha256=71Mcja8jCQqiqFHPdsIXplFIHTvgkxRhp0TRXuCfgkk,7430
113
113
  services/storage_module.py,sha256=ybTMqmvGaTrR8PqJ4FU0cwxaDjT36TskVrGoetTGmno,6955
114
- digitalkin-0.3.1.dev0.dist-info/METADATA,sha256=orxFRM6GJLgC6DrDpmpzlrtK17hop_3x3rqagEEWu_k,29720
115
- digitalkin-0.3.1.dev0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
116
- digitalkin-0.3.1.dev0.dist-info/top_level.txt,sha256=gcjqlyrZuLjIyxrOIavCQM_olpr6ND5kPKkZd2j0xGo,40
117
- digitalkin-0.3.1.dev0.dist-info/RECORD,,
114
+ digitalkin-0.3.1.dev1.dist-info/METADATA,sha256=Aw7Z4ekcYlhBCCGu7x1gut_2YhOaOvxCoWlNPNBgAOU,29720
115
+ digitalkin-0.3.1.dev1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
116
+ digitalkin-0.3.1.dev1.dist-info/top_level.txt,sha256=gcjqlyrZuLjIyxrOIavCQM_olpr6ND5kPKkZd2j0xGo,40
117
+ digitalkin-0.3.1.dev1.dist-info/RECORD,,