Use Hypercorn for republisher serve

This commit is contained in:
Abel Luck 2026-03-31 12:47:36 +02:00
parent 73617cd40c
commit c04efeb189
7 changed files with 133 additions and 9 deletions

View file

@ -1,7 +1,8 @@
import io
import logging
from collections.abc import Awaitable, Callable
from types import SimpleNamespace
from typing import cast
from typing import Any, cast
from repub.entrypoint import FeedNameFilter, entrypoint, logger, parse_args
@ -69,19 +70,44 @@ def test_entrypoint_passes_dev_mode_to_create_app(monkeypatch) -> None:
recorded: dict[str, object] = {}
class StubApp:
def run(self, *, host: str, port: int) -> None:
recorded["host"] = host
recorded["port"] = port
def __init__(self) -> None:
self.extensions: dict[str, object] = {}
def fake_create_app(*, dev_mode: bool) -> StubApp:
recorded["dev_mode"] = dev_mode
return StubApp()
def fake_install_signal_handlers(stop_event: object) -> None:
recorded["stop_event"] = stop_event
async def fake_hypercorn_serve(
app: StubApp,
config: Any,
*,
shutdown_trigger: Callable[[], Awaitable[None]],
) -> None:
recorded["app"] = app
recorded["host"] = config.bind[0].split(":")[0]
recorded["port"] = int(config.bind[0].split(":")[1])
recorded["shutdown_trigger"] = shutdown_trigger
shutdown_event = cast(Any, app.extensions["repub.shutdown_event"])
recorded["app_shutdown_event"] = shutdown_event
shutdown_event.set()
await shutdown_trigger()
monkeypatch.setattr("repub.entrypoint.create_app", fake_create_app)
monkeypatch.setattr(
"repub.entrypoint._install_signal_handlers", fake_install_signal_handlers
)
monkeypatch.setattr("repub.entrypoint.hypercorn_serve", fake_hypercorn_serve)
exit_code = entrypoint(
["serve", "--dev-mode", "--host", "0.0.0.0", "--port", "9090"]
)
assert exit_code == 0
assert recorded == {"dev_mode": True, "host": "0.0.0.0", "port": 9090}
assert recorded["dev_mode"] is True
assert recorded["host"] == "0.0.0.0"
assert recorded["port"] == 9090
assert recorded["stop_event"] is recorded["app_shutdown_event"]
assert callable(recorded["shutdown_trigger"])

View file

@ -548,6 +548,30 @@ def test_render_stream_uses_view_transition_for_queue_reorders() -> None:
asyncio.run(run())
def test_render_stream_stops_when_shutdown_is_requested() -> None:
async def run() -> None:
queue = RefreshBroker().subscribe()
shutdown_event = asyncio.Event()
async def render() -> str:
return '<main id="morph">queue</main>'
stream = render_stream(
queue,
render,
render_on_connect=False,
shutdown_event=shutdown_event,
)
next_event = asyncio.create_task(anext(stream))
await asyncio.sleep(0)
shutdown_event.set()
with pytest.raises(StopAsyncIteration):
await asyncio.wait_for(next_event, timeout=1)
await stream.aclose()
asyncio.run(run())
def test_render_dashboard_shows_dashboard_information_architecture(
monkeypatch, tmp_path: Path
) -> None: