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