import abc import asyncio from utils.value import AttributeChange def fire_and_forget(coro): """asyncio.create_task(), tolerant of there being no running event loop. An actor's observable attribute (e.g. Connectable.connected) can change as a side effect of the server's own final best-effort hardware-release cleanup (server/brewpi.py's `finally:` block - heater.close()/ stirrer.activate(False)), which runs after the loop has already stopped. There's nobody left to notify at that point anyway, so this just drops the message instead of crashing the shutdown sequence.""" try: return asyncio.create_task(coro) except RuntimeError: coro.close() return None class ATask(AttributeChange): def __init__(self, interval): AttributeChange.__init__(self) self.interval = interval @abc.abstractmethod def on_process(self): pass class TaskManager: def __init__(self): self.tasks = [] def add(self, task: ATask): self.tasks.append(task) def start(self): funcs = [] for task in self.tasks: funcs.append(task.on_process()) return asyncio.gather(*funcs)