Coverage for src / lexigram / admin / integrations / tasks.py: 68%
41 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-13 22:14 +0800
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-13 22:14 +0800
1"""Tasks integration — dispatches bulk actions through a task queue."""
3from __future__ import annotations
5from typing import TYPE_CHECKING, Any
7if TYPE_CHECKING:
8 from lexigram.contracts.core.di import (
9 ContainerRegistrarProtocol,
10 ContainerResolverProtocol,
11 )
14class _NoOpTasks:
15 async def dispatch(
16 self, runner: str, action_name: str, record_ids: list[str], ctx_summary: str
17 ) -> dict[str, Any]:
18 return {"status": "noop"}
21class TasksIntegration:
22 """Adapter that dispatches bulk actions via lexigram-tasks.
24 Gracefully no-ops when ``lexigram-tasks`` is not installed or the
25 integration is disabled.
26 """
28 def __init__(self, config: Any) -> None:
29 self._config = config
30 self._tasks: Any = None
31 self._enabled = False
33 def register(self, container: ContainerRegistrarProtocol) -> None:
34 from lexigram.admin.config import TasksIntegrationConfig
35 from lexigram.admin.integrations._optional import is_installed
37 cfg = self._config
38 if not isinstance(cfg, TasksIntegrationConfig):
39 cfg = TasksIntegrationConfig()
40 if not cfg.enabled:
41 self._tasks = _NoOpTasks()
42 return
43 if not is_installed("lexigram.tasks"):
44 self._tasks = _NoOpTasks()
45 return
46 self._enabled = True
48 async def boot(self, container: ContainerResolverProtocol) -> None:
49 if not self._enabled:
50 return
51 try:
52 from lexigram.contracts.infra.tasks import TaskQueueProtocol
54 self._tasks = await container.resolve(TaskQueueProtocol)
55 except Exception: # noqa: BLE001
56 self._tasks = _NoOpTasks()
58 async def shutdown(self) -> None:
59 pass
61 async def health_check(self) -> dict[str, Any]:
62 return {
63 "status": "healthy" if not isinstance(self._tasks, _NoOpTasks) else "noop"
64 }
66 async def dispatch(
67 self,
68 runner: str,
69 action_name: str,
70 record_ids: list[str],
71 ctx_summary: str,
72 ) -> dict[str, Any]:
73 return await self._tasks.dispatch(runner, action_name, record_ids, ctx_summary)
75 @property
76 def threshold(self) -> int:
77 return getattr(self._config, "bulk_threshold", 25)
80__all__ = ["TasksIntegration"]