72 lines
2.6 KiB
Python
72 lines
2.6 KiB
Python
import asyncio
|
|
import logging
|
|
import time
|
|
from typing import Awaitable, Callable
|
|
|
|
from ..checkmk import CheckmkClient
|
|
from ..models import Event
|
|
from ..routing import Route, delay_provider
|
|
from .events import compute_events
|
|
from .options import PollOptions, read_poll_options
|
|
from .state import StateStore
|
|
from .status import PollerStatus
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
ERROR_MAX = 200
|
|
|
|
EventSink = Callable[[list[Event]], Awaitable[None]]
|
|
RuleSource = Callable[[], list[Route]]
|
|
|
|
|
|
class Poller:
|
|
def __init__(self, store, state: StateStore, sink: EventSink, status: PollerStatus,
|
|
client_factory: Callable[[], CheckmkClient | None] | None = None,
|
|
clock: Callable[[], float] = time.time, rules: RuleSource | None = None):
|
|
self._store = store
|
|
self._state = state
|
|
self._sink = sink
|
|
self.status = status
|
|
self._client_factory = client_factory or (lambda: CheckmkClient.from_settings(store))
|
|
self._clock = clock
|
|
self._rules = rules or (lambda: [])
|
|
|
|
async def run(self) -> None:
|
|
while True:
|
|
options = read_poll_options(self._store)
|
|
self.status.interval = options.interval
|
|
try:
|
|
await self.run_cycle(options)
|
|
except asyncio.CancelledError:
|
|
raise
|
|
except Exception:
|
|
log.exception("Poller-Zyklus fehlgeschlagen")
|
|
await asyncio.sleep(options.interval)
|
|
|
|
async def run_cycle(self, options: PollOptions | None = None) -> None:
|
|
options = options or read_poll_options(self._store)
|
|
client = self._client_factory()
|
|
if client is None:
|
|
return
|
|
try:
|
|
current = await client.problem_services()
|
|
except Exception as exc:
|
|
self.status.last_error = f"{type(exc).__name__}: {exc}"[:ERROR_MAX]
|
|
log.warning("Checkmk-Abfrage fehlgeschlagen: %s", self.status.last_error)
|
|
return
|
|
finally:
|
|
await client.aclose()
|
|
now = int(self._clock())
|
|
previous = await asyncio.to_thread(self._state.load)
|
|
rules = await asyncio.to_thread(self._rules)
|
|
delay = delay_provider(rules, options.default_delay_minutes)
|
|
events, rows = compute_events(previous, current, now, delay)
|
|
await asyncio.to_thread(self._state.apply, previous, rows, now)
|
|
self.status.last_success = self._clock()
|
|
self.status.last_error = None
|
|
if events:
|
|
try:
|
|
await self._sink(events)
|
|
except Exception:
|
|
log.exception("Verarbeitung der Events fehlgeschlagen")
|