Add support for listener and signal prioritization
This commit is contained in:
parent
86a414fd58
commit
0dd1948fd2
20
sanic/app.py
20
sanic/app.py
|
@ -432,7 +432,7 @@ class Sanic(
|
|||
# -------------------------------------------------------------------- #
|
||||
|
||||
def register_listener(
|
||||
self, listener: ListenerType[SanicVar], event: str
|
||||
self, listener: ListenerType[SanicVar], event: str, *, priority: int = 0
|
||||
) -> ListenerType[SanicVar]:
|
||||
"""Register the listener for a given event.
|
||||
|
||||
|
@ -453,10 +453,14 @@ class Sanic(
|
|||
raise BadRequest(f"Invalid event: {event}. Use one of: {valid}")
|
||||
|
||||
if "." in _event:
|
||||
self.signal(_event.value)(
|
||||
self.signal(_event.value, priority=priority)(
|
||||
partial(self._listener, listener=listener)
|
||||
)
|
||||
else:
|
||||
if priority:
|
||||
error_logger.warning(
|
||||
f"Priority is not supported for {_event.value}"
|
||||
)
|
||||
self.listeners[_event.value].append(listener)
|
||||
|
||||
return listener
|
||||
|
@ -580,7 +584,7 @@ class Sanic(
|
|||
return handler.handler
|
||||
|
||||
def _apply_listener(self, listener: FutureListener):
|
||||
return self.register_listener(listener.listener, listener.event)
|
||||
return self.register_listener(listener.listener, listener.event, priority=listener.priority)
|
||||
|
||||
def _apply_route(
|
||||
self, route: FutureRoute, overwrite: bool = False
|
||||
|
@ -632,7 +636,13 @@ class Sanic(
|
|||
|
||||
def _apply_signal(self, signal: FutureSignal) -> Signal:
|
||||
with self.amend():
|
||||
return self.signal_router.add(*signal)
|
||||
return self.signal_router.add(
|
||||
handler=signal.handler,
|
||||
event=signal.event,
|
||||
condition=signal.condition,
|
||||
exclusive=signal.exclusive,
|
||||
priority=signal.priority,
|
||||
)
|
||||
|
||||
@overload
|
||||
def dispatch(
|
||||
|
@ -1399,7 +1409,7 @@ class Sanic(
|
|||
if not hasattr(handler, "is_websocket"):
|
||||
raise ServerError(
|
||||
f"Invalid response type {response!r} "
|
||||
"(need HTTPResponse)"
|
||||
"(need HTTPResponse)"
|
||||
)
|
||||
|
||||
except CancelledError: # type: ignore
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from enum import Enum, auto
|
||||
from functools import partial
|
||||
from typing import Callable, List, Optional, Union, overload
|
||||
|
||||
from operator import attrgetter
|
||||
from sanic.base.meta import SanicMeta
|
||||
from sanic.exceptions import BadRequest
|
||||
from sanic.models.futures import FutureListener
|
||||
|
@ -38,6 +38,8 @@ class ListenerMixin(metaclass=SanicMeta):
|
|||
listener_or_event: ListenerType[Sanic],
|
||||
event_or_none: str,
|
||||
apply: bool = ...,
|
||||
*,
|
||||
priority: int = 0,
|
||||
) -> ListenerType[Sanic]:
|
||||
...
|
||||
|
||||
|
@ -47,6 +49,8 @@ class ListenerMixin(metaclass=SanicMeta):
|
|||
listener_or_event: str,
|
||||
event_or_none: None = ...,
|
||||
apply: bool = ...,
|
||||
*,
|
||||
priority: int = 0,
|
||||
) -> Callable[[ListenerType[Sanic]], ListenerType[Sanic]]:
|
||||
...
|
||||
|
||||
|
@ -55,6 +59,8 @@ class ListenerMixin(metaclass=SanicMeta):
|
|||
listener_or_event: Union[ListenerType[Sanic], str],
|
||||
event_or_none: Optional[str] = None,
|
||||
apply: bool = True,
|
||||
*,
|
||||
priority: int = 0,
|
||||
) -> Union[
|
||||
ListenerType[Sanic],
|
||||
Callable[[ListenerType[Sanic]], ListenerType[Sanic]],
|
||||
|
@ -81,6 +87,7 @@ class ListenerMixin(metaclass=SanicMeta):
|
|||
listener_or_event (Union[ListenerType[Sanic], str]): A listener function or an event name.
|
||||
event_or_none (Optional[str]): The event name to listen for if `listener_or_event` is a function. Defaults to `None`.
|
||||
apply (bool): Whether to apply the listener immediately. Defaults to `True`.
|
||||
priority (int): The priority of the listener. Defaults to `0`.
|
||||
|
||||
Returns:
|
||||
Union[ListenerType[Sanic], Callable[[ListenerType[Sanic]], ListenerType[Sanic]]]: The listener or a callable that takes a listener.
|
||||
|
@ -96,7 +103,7 @@ class ListenerMixin(metaclass=SanicMeta):
|
|||
""" # noqa: E501
|
||||
|
||||
def register_listener(
|
||||
listener: ListenerType[Sanic], event: str
|
||||
listener: ListenerType[Sanic], event: str, priority: int = 0
|
||||
) -> ListenerType[Sanic]:
|
||||
"""A helper function to register a listener for an event.
|
||||
|
||||
|
@ -112,7 +119,7 @@ class ListenerMixin(metaclass=SanicMeta):
|
|||
"""
|
||||
nonlocal apply
|
||||
|
||||
future_listener = FutureListener(listener, event)
|
||||
future_listener = FutureListener(listener, event, priority)
|
||||
self._future_listeners.append(future_listener)
|
||||
if apply:
|
||||
self._apply_listener(future_listener)
|
||||
|
@ -123,9 +130,9 @@ class ListenerMixin(metaclass=SanicMeta):
|
|||
raise BadRequest(
|
||||
"Invalid event registration: Missing event name."
|
||||
)
|
||||
return register_listener(listener_or_event, event_or_none)
|
||||
return register_listener(listener_or_event, event_or_none, priority)
|
||||
else:
|
||||
return partial(register_listener, event=listener_or_event)
|
||||
return partial(register_listener, event=listener_or_event, priority=priority)
|
||||
|
||||
def main_process_start(
|
||||
self, listener: ListenerType[Sanic]
|
||||
|
|
|
@ -24,6 +24,7 @@ class SignalMixin(metaclass=SanicMeta):
|
|||
apply: bool = True,
|
||||
condition: Optional[Dict[str, Any]] = None,
|
||||
exclusive: bool = True,
|
||||
priority: int = 0,
|
||||
) -> Callable[[SignalHandler], SignalHandler]:
|
||||
"""
|
||||
For creating a signal handler, used similar to a route handler:
|
||||
|
@ -51,7 +52,7 @@ class SignalMixin(metaclass=SanicMeta):
|
|||
|
||||
def decorator(handler: SignalHandler):
|
||||
future_signal = FutureSignal(
|
||||
handler, event_value, HashableDict(condition or {}), exclusive
|
||||
handler, event_value, HashableDict(condition or {}), exclusive, priority
|
||||
)
|
||||
self._future_signals.add(future_signal)
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ class FutureRoute(NamedTuple):
|
|||
class FutureListener(NamedTuple):
|
||||
listener: ListenerType
|
||||
event: str
|
||||
priority: int
|
||||
|
||||
|
||||
class FutureMiddleware(NamedTuple):
|
||||
|
@ -65,6 +66,7 @@ class FutureSignal(NamedTuple):
|
|||
event: str
|
||||
condition: Optional[Dict[str, str]]
|
||||
exclusive: bool
|
||||
priority: int
|
||||
|
||||
|
||||
class FutureRegistry(set):
|
||||
|
|
|
@ -250,6 +250,8 @@ class SignalRouter(BaseRouter):
|
|||
event: str,
|
||||
condition: Optional[Dict[str, Any]] = None,
|
||||
exclusive: bool = True,
|
||||
*,
|
||||
priority: int = 0,
|
||||
) -> Signal:
|
||||
event_definition = event
|
||||
parts = self._build_event_parts(event)
|
||||
|
@ -268,6 +270,7 @@ class SignalRouter(BaseRouter):
|
|||
handler,
|
||||
name=name,
|
||||
append=True,
|
||||
priority=priority,
|
||||
) # type: ignore
|
||||
|
||||
signal.ctx.exclusive = exclusive
|
||||
|
|
Loading…
Reference in New Issue
Block a user