You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
iTi-Flask/iti/events/bus.py

41 lines
1.3 KiB
Python

from __future__ import annotations
import logging
from collections import defaultdict
from collections.abc import Callable
from concurrent.futures import ThreadPoolExecutor
logger = logging.getLogger("iti.events")
class EventBus:
def __init__(self, *, max_workers: int = 10) -> None:
self._handlers: dict[str, list[Callable]] = defaultdict(list)
self._executor = ThreadPoolExecutor(max_workers=max_workers)
def on(self, event_name: str):
def decorator(func: Callable) -> Callable:
self.register_handler(event_name, func)
return func
return decorator
def register_handler(self, event_name: str, handler: Callable) -> None:
self._handlers[event_name].append(handler)
def emit(self, event_name: str, *args, async_mode: bool = False, **kwargs) -> None:
for handler in list(self._handlers.get(event_name, [])):
if async_mode:
self._executor.submit(self._run_handler, handler, *args, **kwargs)
else:
self._run_handler(handler, *args, **kwargs)
def _run_handler(self, handler: Callable, *args, **kwargs) -> None:
try:
handler(*args, **kwargs)
except Exception:
logger.exception("event handler failed: %s", handler)
eventbus = EventBus()