service.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. # -*- coding: utf-8 -*-
  2. """
  3. Scheduler Service - IService Wrapper für Scheduler.
  4. """
  5. from typing import TYPE_CHECKING
  6. from trixy_core.service import IService, ServicePriority, ServiceGroup
  7. from trixy_core.scheduler.scheduler import Scheduler, SchedulerConfig
  8. from trixy_core.scheduler.job import ScheduledJob, JobConfig, JobResult
  9. from trixy_core.scheduler.trigger.base import Trigger
  10. from trixy_core.scheduler.condition.base import Condition
  11. from trixy_core.scheduler.action.base import Action
  12. if TYPE_CHECKING:
  13. from trixy_core.application import IApplication
  14. from trixy_core.events import EventManager
  15. class SchedulerService(IService):
  16. """
  17. Scheduler als IService für Integration in ServiceContainer.
  18. Beispiel:
  19. ```python
  20. scheduler_service = SchedulerService(app, config)
  21. container.register_instance(scheduler_service)
  22. ```
  23. """
  24. PRIORITY = ServicePriority.MANAGER
  25. GROUP = ServiceGroup.SCHEDULER
  26. DEPENDENCIES: list[str] = []
  27. def __init__(
  28. self,
  29. application: "IApplication",
  30. config: SchedulerConfig | None = None,
  31. ):
  32. """
  33. Initialisiert den Scheduler-Service.
  34. Args:
  35. application: Referenz zur Hauptanwendung
  36. config: Scheduler-Konfiguration
  37. """
  38. super().__init__(application)
  39. self._config = config or SchedulerConfig()
  40. self._scheduler: Scheduler | None = None
  41. self._event_manager: "EventManager | None" = None
  42. @property
  43. def scheduler(self) -> Scheduler | None:
  44. """Scheduler-Instanz."""
  45. return self._scheduler
  46. # === IService Lifecycle ===
  47. async def start(self) -> None:
  48. """Startet den Service."""
  49. pass
  50. async def stop(self) -> None:
  51. """Stoppt den Service."""
  52. pass
  53. async def on_pre_start(self) -> None:
  54. """Vorbereitung vor Start."""
  55. self._event_manager = self._application.events
  56. self._scheduler = Scheduler(
  57. config=self._config,
  58. event_manager=self._event_manager,
  59. )
  60. async def on_post_start(self) -> None:
  61. """Nach Start - Scheduler starten."""
  62. if self._scheduler:
  63. # Applikation und Manager in Kontext injizieren
  64. self._scheduler.set_context("application", self._application)
  65. self._scheduler.set_context("event_manager", self._event_manager)
  66. satellites = getattr(self._application, "satellites", None)
  67. if satellites is not None:
  68. self._scheduler.set_context("satellite_manager", satellites)
  69. await self._scheduler.start()
  70. # Events abonnieren für EventTrigger
  71. if self._event_manager:
  72. @self._event_manager.on("*")
  73. async def on_any_event(event_name: str, event_data: dict) -> None:
  74. if self._scheduler:
  75. await self._scheduler.on_event(event_name, event_data)
  76. async def on_pre_stop(self) -> None:
  77. """Vor Stop - Scheduler stoppen."""
  78. if self._scheduler:
  79. await self._scheduler.stop()
  80. # === Job-Verwaltung (Proxies) ===
  81. def add_job(
  82. self,
  83. job: ScheduledJob,
  84. save: bool | None = None,
  85. ) -> str:
  86. """Fügt Job hinzu."""
  87. if not self._scheduler:
  88. raise RuntimeError("Scheduler nicht initialisiert")
  89. return self._scheduler.add_job(job, save)
  90. def create_job(
  91. self,
  92. trigger: Trigger,
  93. actions: list[Action] | Action,
  94. conditions: list[Condition] | None = None,
  95. config: JobConfig | None = None,
  96. job_id: str | None = None,
  97. save: bool | None = None,
  98. ) -> ScheduledJob:
  99. """Erstellt und fügt Job hinzu."""
  100. if not self._scheduler:
  101. raise RuntimeError("Scheduler nicht initialisiert")
  102. return self._scheduler.create_job(
  103. trigger=trigger,
  104. actions=actions,
  105. conditions=conditions,
  106. config=config,
  107. job_id=job_id,
  108. save=save,
  109. )
  110. def get_job(self, job_id: str) -> ScheduledJob | None:
  111. """Holt Job nach ID."""
  112. if self._scheduler:
  113. return self._scheduler.get_job(job_id)
  114. return None
  115. def remove_job(self, job_id: str, delete_file: bool = True) -> bool:
  116. """Entfernt Job."""
  117. if self._scheduler:
  118. return self._scheduler.remove_job(job_id, delete_file)
  119. return False
  120. def enable_job(self, job_id: str) -> bool:
  121. """Aktiviert Job."""
  122. if self._scheduler:
  123. return self._scheduler.enable_job(job_id)
  124. return False
  125. def disable_job(self, job_id: str) -> bool:
  126. """Deaktiviert Job."""
  127. if self._scheduler:
  128. return self._scheduler.disable_job(job_id)
  129. return False
  130. @property
  131. def jobs(self) -> dict[str, ScheduledJob]:
  132. """Alle Jobs."""
  133. if self._scheduler:
  134. return self._scheduler.jobs
  135. return {}
  136. @property
  137. def job_count(self) -> int:
  138. """Anzahl Jobs."""
  139. if self._scheduler:
  140. return self._scheduler.job_count
  141. return 0
  142. # === Context ===
  143. def set_context(self, key: str, value) -> None:
  144. """Setzt Kontext-Variable."""
  145. if self._scheduler:
  146. self._scheduler.set_context(key, value)
  147. def update_context(self, data: dict) -> None:
  148. """Aktualisiert Kontext."""
  149. if self._scheduler:
  150. self._scheduler.update_context(data)
  151. # === Statistics ===
  152. def get_statistics(self) -> dict:
  153. """Gibt Scheduler-Statistiken zurück."""
  154. if self._scheduler:
  155. return self._scheduler.get_statistics()
  156. return {}