|
40 | 40 | UnaryResponseDefinition, |
41 | 41 | ) |
42 | 42 | from google.protobuf.any_pb2 import Any |
43 | | -from hypercorn.config import Config as HypercornConfig |
44 | | -from hypercorn.logging import Logger |
45 | 43 |
|
46 | 44 | from connectrpc.code import Code |
47 | 45 | from connectrpc.errors import ConnectError |
@@ -389,22 +387,6 @@ def bidi_stream( |
389 | 387 | ) |
390 | 388 |
|
391 | 389 |
|
392 | | -class PortCapturingLogger(Logger): |
393 | | - """In-memory logger for Hypercorn, useful for testing.""" |
394 | | - |
395 | | - port = -1 |
396 | | - |
397 | | - def __init__(self, conf: HypercornConfig) -> None: |
398 | | - super().__init__(conf) |
399 | | - |
400 | | - async def info(self, message: str, *args: Any, **kwargs: Any) -> None: |
401 | | - if "Running on" in message: |
402 | | - _, _, rest = message.partition("//127.0.0.1:") |
403 | | - port, _, _ = rest.partition(" ") |
404 | | - self.port = int(port) |
405 | | - await super().info(message, *args, **kwargs) |
406 | | - |
407 | | - |
408 | 390 | read_max_bytes = os.getenv("READ_MAX_BYTES") |
409 | 391 | if read_max_bytes is not None: |
410 | 392 | read_max_bytes = int(read_max_bytes) |
@@ -432,6 +414,23 @@ def _server_env(request: ServerCompatRequest) -> dict[str, str]: |
432 | 414 | _port_regex = re.compile(r".*://[^:]+:(\d+).*") |
433 | 415 |
|
434 | 416 |
|
| 417 | +async def _tee_to_stderr(stream: asyncio.StreamReader) -> AsyncIterator[bytes]: |
| 418 | + try: |
| 419 | + while True: |
| 420 | + line = await stream.readline() |
| 421 | + if not line: |
| 422 | + break |
| 423 | + print(line.decode("utf-8"), end="", file=sys.stderr) # noqa: T201 |
| 424 | + yield line |
| 425 | + except asyncio.CancelledError: |
| 426 | + pass |
| 427 | + |
| 428 | + |
| 429 | +async def _consume_log(stream: AsyncIterator[bytes]) -> None: |
| 430 | + async for _ in stream: |
| 431 | + pass |
| 432 | + |
| 433 | + |
435 | 434 | async def serve_granian( |
436 | 435 | request: ServerCompatRequest, |
437 | 436 | mode: Literal["sync", "async"], |
@@ -470,12 +469,13 @@ async def serve_granian( |
470 | 469 | ) |
471 | 470 | stdout = proc.stdout |
472 | 471 | assert stdout is not None # noqa: S101 |
| 472 | + stdout = _tee_to_stderr(stdout) |
473 | 473 | try: |
474 | | - for _ in range(100): |
475 | | - line = await stdout.readline() |
| 474 | + async for line in stdout: |
476 | 475 | if b"Started worker-1 runtime-1" in line: |
477 | 476 | break |
478 | 477 | port_future.set_result(port) |
| 478 | + await _consume_log(stdout) |
479 | 479 | await proc.wait() |
480 | 480 | except asyncio.CancelledError: |
481 | 481 | proc.terminate() |
@@ -510,21 +510,14 @@ async def serve_gunicorn( |
510 | 510 | ) |
511 | 511 | stdout = proc.stdout |
512 | 512 | assert stdout is not None # noqa: S101 |
513 | | - port = None |
| 513 | + stdout = _tee_to_stderr(stdout) |
514 | 514 | try: |
515 | | - for _ in range(100): |
516 | | - line = await stdout.readline() |
| 515 | + async for line in stdout: |
517 | 516 | match = _port_regex.match(line.decode("utf-8")) |
518 | 517 | if match: |
519 | | - port = int(match.group(1)) |
520 | | - break |
521 | | - if b"Booting worker with pid" in line: |
| 518 | + port_future.set_result(int(match.group(1))) |
522 | 519 | break |
523 | | - if port is None: |
524 | | - msg = "Could not determine port from gunicorn output" |
525 | | - raise RuntimeError(msg) |
526 | | - port_future.set_result(port) |
527 | | - await proc.wait() |
| 520 | + await _consume_log(stdout) |
528 | 521 | except asyncio.CancelledError: |
529 | 522 | proc.terminate() |
530 | 523 | await proc.wait() |
@@ -562,14 +555,14 @@ async def serve_hypercorn( |
562 | 555 | ) |
563 | 556 | stdout = proc.stdout |
564 | 557 | assert stdout is not None # noqa: S101 |
| 558 | + stdout = _tee_to_stderr(stdout) |
565 | 559 | try: |
566 | | - for _ in range(100): |
567 | | - line = await stdout.readline() |
| 560 | + async for line in stdout: |
568 | 561 | match = _port_regex.match(line.decode("utf-8")) |
569 | 562 | if match: |
570 | 563 | port_future.set_result(int(match.group(1))) |
571 | 564 | break |
572 | | - await proc.wait() |
| 565 | + await _consume_log(stdout) |
573 | 566 | except asyncio.CancelledError: |
574 | 567 | proc.terminate() |
575 | 568 | await proc.wait() |
@@ -603,14 +596,14 @@ async def serve_uvicorn( |
603 | 596 | ) |
604 | 597 | stdout = proc.stdout |
605 | 598 | assert stdout is not None # noqa: S101 |
| 599 | + stdout = _tee_to_stderr(stdout) |
606 | 600 | try: |
607 | | - for _ in range(100): |
608 | | - line = await stdout.readline() |
| 601 | + async for line in stdout: |
609 | 602 | match = _port_regex.match(line.decode("utf-8")) |
610 | 603 | if match: |
611 | 604 | port_future.set_result(int(match.group(1))) |
612 | 605 | break |
613 | | - await proc.wait() |
| 606 | + await _consume_log(stdout) |
614 | 607 | except asyncio.CancelledError: |
615 | 608 | proc.terminate() |
616 | 609 | await proc.wait() |
|
0 commit comments