Event autoregister (#2140)

* Add event autoregistration

* Setup tests

* Cleanup IDE added imports

* Remove unused imports
This commit is contained in:
Adam Hopkins 2021-06-01 10:44:07 +03:00 committed by GitHub
parent 16875b1f41
commit 0c3a8392f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 82 additions and 24 deletions

View File

@ -382,11 +382,19 @@ class Sanic(BaseSanic):
condition=condition,
)
def event(self, event: str, timeout: Optional[Union[int, float]] = None):
async def event(
self, event: str, timeout: Optional[Union[int, float]] = None
):
signal = self.signal_router.name_index.get(event)
if not signal:
raise NotFound("Could not find signal %s" % event)
return wait_for(signal.ctx.event.wait(), timeout=timeout)
if self.config.EVENT_AUTOREGISTER:
self.signal_router.reset()
self.add_signal(None, event)
signal = self.signal_router.name_index.get(event)
self.signal_router.finalize()
else:
raise NotFound("Could not find signal %s" % event)
return await wait_for(signal.ctx.event.wait(), timeout=timeout)
def enable_websocket(self, enable=True):
"""Enable or disable the support for websocket.

View File

@ -16,28 +16,29 @@ BASE_LOGO = """
"""
DEFAULT_CONFIG = {
"REQUEST_MAX_SIZE": 100000000, # 100 megabytes
"ACCESS_LOG": True,
"EVENT_AUTOREGISTER": False,
"FALLBACK_ERROR_FORMAT": "html",
"FORWARDED_FOR_HEADER": "X-Forwarded-For",
"FORWARDED_SECRET": None,
"GRACEFUL_SHUTDOWN_TIMEOUT": 15.0, # 15 sec
"KEEP_ALIVE_TIMEOUT": 5, # 5 seconds
"KEEP_ALIVE": True,
"PROXIES_COUNT": None,
"REAL_IP_HEADER": None,
"REGISTER": True,
"REQUEST_BUFFER_QUEUE_SIZE": 100,
"REQUEST_BUFFER_SIZE": 65536, # 64 KiB
"REQUEST_ID_HEADER": "X-Request-ID",
"REQUEST_MAX_SIZE": 100000000, # 100 megabytes
"REQUEST_TIMEOUT": 60, # 60 seconds
"RESPONSE_TIMEOUT": 60, # 60 seconds
"KEEP_ALIVE": True,
"KEEP_ALIVE_TIMEOUT": 5, # 5 seconds
"WEBSOCKET_MAX_SIZE": 2 ** 20, # 1 megabyte
"WEBSOCKET_MAX_QUEUE": 32,
"WEBSOCKET_MAX_SIZE": 2 ** 20, # 1 megabyte
"WEBSOCKET_PING_INTERVAL": 20,
"WEBSOCKET_PING_TIMEOUT": 20,
"WEBSOCKET_READ_LIMIT": 2 ** 16,
"WEBSOCKET_WRITE_LIMIT": 2 ** 16,
"WEBSOCKET_PING_TIMEOUT": 20,
"WEBSOCKET_PING_INTERVAL": 20,
"GRACEFUL_SHUTDOWN_TIMEOUT": 15.0, # 15 sec
"ACCESS_LOG": True,
"FORWARDED_SECRET": None,
"REAL_IP_HEADER": None,
"PROXIES_COUNT": None,
"FORWARDED_FOR_HEADER": "X-Forwarded-For",
"REQUEST_ID_HEADER": "X-Request-ID",
"FALLBACK_ERROR_FORMAT": "html",
"REGISTER": True,
}

View File

@ -1,4 +1,4 @@
from typing import Any, Callable, Dict, Set
from typing import Any, Callable, Dict, Optional, Set
from sanic.models.futures import FutureSignal
from sanic.models.handler_types import SignalHandler
@ -60,10 +60,16 @@ class SignalMixin:
def add_signal(
self,
handler,
handler: Optional[Callable[..., Any]],
event: str,
condition: Dict[str, Any] = None,
):
if not handler:
async def noop():
...
handler = noop
self.signal(event=event, condition=condition)(handler)
return handler

View File

@ -257,17 +257,60 @@ def test_bad_finalize(app):
assert counter == 0
def test_event_not_exist(app):
@pytest.mark.asyncio
async def test_event_not_exist(app):
with pytest.raises(NotFound, match="Could not find signal does.not.exist"):
app.event("does.not.exist")
await app.event("does.not.exist")
def test_event_not_exist_on_bp(app):
@pytest.mark.asyncio
async def test_event_not_exist_on_bp(app):
bp = Blueprint("bp")
app.blueprint(bp)
with pytest.raises(NotFound, match="Could not find signal does.not.exist"):
bp.event("does.not.exist")
await bp.event("does.not.exist")
@pytest.mark.asyncio
async def test_event_not_exist_with_autoregister(app):
app.config.EVENT_AUTOREGISTER = True
try:
await app.event("does.not.exist", timeout=0.1)
except asyncio.TimeoutError:
...
@pytest.mark.asyncio
async def test_dispatch_signal_triggers_non_exist_event_with_autoregister(app):
@app.signal("some.stand.in")
async def signal_handler():
...
app.config.EVENT_AUTOREGISTER = True
app_counter = 0
app.signal_router.finalize()
async def do_wait():
nonlocal app_counter
await app.event("foo.bar.baz")
app_counter += 1
fut = asyncio.ensure_future(do_wait())
await app.dispatch("foo.bar.baz")
await fut
assert app_counter == 1
@pytest.mark.asyncio
async def test_dispatch_not_exist(app):
@app.signal("do.something.start")
async def signal_handler():
...
app.signal_router.finalize()
await app.dispatch("does.not.exist")
def test_event_on_bp_not_registered():