event handlers are now executed in separate tasks
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
# SPDX-License-Identifier: BSD 2-Clause License
|
||||
#
|
||||
|
||||
import asyncio
|
||||
import inspect
|
||||
from abc import ABC
|
||||
from typing import Optional
|
||||
@@ -17,8 +18,15 @@ class BaseObject(ABC):
|
||||
def __init__(self, *, name: Optional[str] = None):
|
||||
self._id: int = obj_id()
|
||||
self._name = name or f"{self.__class__.__name__}#{obj_count(self)}"
|
||||
|
||||
# Registered event handlers.
|
||||
self._event_handlers: dict = {}
|
||||
|
||||
# Set of tasks being executed. When a task finishes running it gets
|
||||
# automatically removed from the set. When we cleanup we wait for all
|
||||
# event tasks still being executed.
|
||||
self._event_tasks = set()
|
||||
|
||||
@property
|
||||
def id(self) -> int:
|
||||
return self._id
|
||||
@@ -27,6 +35,12 @@ class BaseObject(ABC):
|
||||
def name(self) -> str:
|
||||
return self._name
|
||||
|
||||
async def cleanup(self):
|
||||
if self._event_tasks:
|
||||
event_names, tasks = zip(*self._event_tasks)
|
||||
logger.debug(f"{self} wating on event handlers to finish {list(event_names)}...")
|
||||
await asyncio.wait(tasks)
|
||||
|
||||
def event_handler(self, event_name: str):
|
||||
def decorator(handler):
|
||||
self.add_event_handler(event_name, handler)
|
||||
@@ -45,6 +59,16 @@ class BaseObject(ABC):
|
||||
self._event_handlers[event_name] = []
|
||||
|
||||
async def _call_event_handler(self, event_name: str, *args, **kwargs):
|
||||
# Create the task.
|
||||
task = asyncio.create_task(self._run_task(event_name, *args, **kwargs))
|
||||
|
||||
# Add it to our list of event tasks.
|
||||
self._event_tasks.add((event_name, task))
|
||||
|
||||
# Remove the task from the event tasks list when the task completes.
|
||||
task.add_done_callback(self._event_task_finished)
|
||||
|
||||
async def _run_task(self, event_name: str, *args, **kwargs):
|
||||
try:
|
||||
for handler in self._event_handlers[event_name]:
|
||||
if inspect.iscoroutinefunction(handler):
|
||||
@@ -54,5 +78,10 @@ class BaseObject(ABC):
|
||||
except Exception as e:
|
||||
logger.exception(f"Exception in event handler {event_name}: {e}")
|
||||
|
||||
def _event_task_finished(self, task: asyncio.Task):
|
||||
tuple_to_remove = next((t for t in self._event_tasks if t[1] == task), None)
|
||||
if tuple_to_remove:
|
||||
self._event_tasks.discard(tuple_to_remove)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
Reference in New Issue
Block a user