Skip to content

Commit e47efeb

Browse files
committed
Unify server dispatch through handler.handle()
Both HTTP/1.1 and HTTP/2 workers now use a single handler.handle() call instead of separate sync/async dispatch paths. The handler manages signals and async view detection internally.
1 parent 0d0c8a6 commit e47efeb

File tree

3 files changed

+8
-73
lines changed

3 files changed

+8
-73
lines changed

plain/plain/server/http/h2handler.py

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import h2.events
1616
import h2.exceptions
1717

18-
from plain import signals
1918
from plain.http import AsyncStreamingResponse, FileResponse, StreamingResponse
2019
from plain.http import Request as HttpRequest
2120

@@ -502,7 +501,6 @@ async def _async_handle_stream(
502501
stream: H2Stream,
503502
) -> None:
504503
"""Process a single completed HTTP/2 stream as an async task."""
505-
loop = asyncio.get_running_loop()
506504
request_start = datetime.now()
507505

508506
try:
@@ -515,26 +513,7 @@ async def _async_handle_stream(
515513
return
516514

517515
try:
518-
signals.request_started.send(
519-
sender=state.handler.__class__, request=http_request
520-
)
521-
522-
# Detect async views — resolve URL in executor to avoid blocking event loop
523-
def _check_async() -> bool:
524-
return hasattr(
525-
state.handler, "is_async_view"
526-
) and state.handler.is_async_view(http_request)
527-
528-
is_async = await loop.run_in_executor(state.executor, _check_async)
529-
530-
if is_async:
531-
http_response = await state.handler.get_response_async(
532-
http_request, state.executor
533-
)
534-
else:
535-
http_response = await loop.run_in_executor(
536-
state.executor, state.handler.get_response, http_request
537-
)
516+
http_response = await state.handler.handle(http_request, state.executor)
538517

539518
try:
540519
if stream.stream_id in state.reset_streams:

plain/plain/server/util.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ def make_fail_handler(msg: str | bytes) -> Any:
185185
msg = to_bytestring(msg)
186186

187187
class FailHandler:
188-
def get_response(self, request: Any) -> Any:
188+
async def handle(self, request: Any, executor: Any) -> Any:
189189
from plain.http import Response
190190

191191
return Response(msg, status_code=500, content_type="text/plain")

plain/plain/server/workers/thread.py

Lines changed: 6 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
from types import FrameType
3030
from typing import TYPE_CHECKING, Any
3131

32-
from plain import signals
3332
from plain.internal.reloader import Reloader
3433

3534
from .. import http, sock, util
@@ -317,26 +316,9 @@ async def _handle_connection(self, conn: TConn) -> None:
317316

318317
req, http_request, resp, request_start = parse_result
319318

320-
# Detect async views (fast, safe on event loop).
321-
# FailHandler (from make_fail_handler) doesn't have this method.
322-
is_async = hasattr(
323-
self.handler, "is_async_view"
324-
) and self.handler.is_async_view(http_request)
325-
326-
if is_async:
327-
keepalive = await self._dispatch_async(
328-
req, conn, http_request, resp, request_start
329-
)
330-
else:
331-
keepalive = await loop.run_in_executor(
332-
self.tpool,
333-
self._dispatch_sync,
334-
req,
335-
conn,
336-
http_request,
337-
resp,
338-
request_start,
339-
)
319+
keepalive = await self._dispatch(
320+
req, conn, http_request, resp, request_start
321+
)
340322

341323
if not keepalive or not self.alive:
342324
break
@@ -627,44 +609,18 @@ def _handle_dispatch_error(
627609
self.handle_error(req, conn.sock, conn.client, exc)
628610
return False
629611

630-
def _dispatch_sync(
631-
self,
632-
req: Any,
633-
conn: TConn,
634-
http_request: Any,
635-
resp: Response,
636-
request_start: datetime,
637-
) -> bool:
638-
"""Sync dispatch: signal + full middleware pipeline + write response."""
639-
try:
640-
signals.request_started.send(sender=self.__class__, request=http_request)
641-
http_response = self.handler.get_response(http_request)
642-
return self._finish_request(req, resp, http_response, request_start)
643-
except Exception as exc:
644-
return self._handle_dispatch_error(req, resp, conn, exc)
645-
646-
async def _dispatch_async(
612+
async def _dispatch(
647613
self,
648614
req: Any,
649615
conn: TConn,
650616
http_request: Any,
651617
resp: Response,
652618
request_start: datetime,
653619
) -> bool:
654-
"""Async dispatch: middleware in thread pool, async view on event loop."""
620+
"""Dispatch a request through the handler and write the response."""
655621
loop = asyncio.get_running_loop()
656622
try:
657-
# Send signal in thread pool (handlers may do sync work)
658-
await loop.run_in_executor(
659-
self.tpool,
660-
lambda: signals.request_started.send(
661-
sender=self.__class__, request=http_request
662-
),
663-
)
664-
# Async middleware pipeline + view
665-
http_response = await self.handler.get_response_async(
666-
http_request, self.tpool
667-
)
623+
http_response = await self.handler.handle(http_request, self.tpool)
668624

669625
# Check for async streaming response (SSE, etc.)
670626
from plain.http import AsyncStreamingResponse

0 commit comments

Comments
 (0)