Wraps a `.Future` (or other yieldable object) in a timeout. Raises `tornado.util.TimeoutError` if the input future does not complete before ``timeout``, which may be specified in any form allowed by `.IOLoop.add_timeout` (i.e. a `datetime.timedelta` or an absolute time relative to `
(
timeout: Union[float, datetime.timedelta],
future: _Yieldable,
quiet_exceptions: "Union[Type[Exception], Tuple[Type[Exception], ...]]" = (),
)
| 574 | |
| 575 | |
| 576 | def with_timeout( |
| 577 | timeout: Union[float, datetime.timedelta], |
| 578 | future: _Yieldable, |
| 579 | quiet_exceptions: "Union[Type[Exception], Tuple[Type[Exception], ...]]" = (), |
| 580 | ) -> Future: |
| 581 | """Wraps a `.Future` (or other yieldable object) in a timeout. |
| 582 | |
| 583 | Raises `tornado.util.TimeoutError` if the input future does not |
| 584 | complete before ``timeout``, which may be specified in any form |
| 585 | allowed by `.IOLoop.add_timeout` (i.e. a `datetime.timedelta` or |
| 586 | an absolute time relative to `.IOLoop.time`) |
| 587 | |
| 588 | If the wrapped `.Future` fails after it has timed out, the exception |
| 589 | will be logged unless it is either of a type contained in |
| 590 | ``quiet_exceptions`` (which may be an exception type or a sequence of |
| 591 | types), or an ``asyncio.CancelledError``. |
| 592 | |
| 593 | The wrapped `.Future` is not canceled when the timeout expires, |
| 594 | permitting it to be reused. `asyncio.wait_for` is similar to this |
| 595 | function but it does cancel the wrapped `.Future` on timeout. |
| 596 | |
| 597 | .. versionadded:: 4.0 |
| 598 | |
| 599 | .. versionchanged:: 4.1 |
| 600 | Added the ``quiet_exceptions`` argument and the logging of unhandled |
| 601 | exceptions. |
| 602 | |
| 603 | .. versionchanged:: 4.4 |
| 604 | Added support for yieldable objects other than `.Future`. |
| 605 | |
| 606 | .. versionchanged:: 6.0.3 |
| 607 | ``asyncio.CancelledError`` is now always considered "quiet". |
| 608 | |
| 609 | .. versionchanged:: 6.2 |
| 610 | ``tornado.util.TimeoutError`` is now an alias to ``asyncio.TimeoutError``. |
| 611 | |
| 612 | """ |
| 613 | # It's tempting to optimize this by cancelling the input future on timeout |
| 614 | # instead of creating a new one, but A) we can't know if we are the only |
| 615 | # one waiting on the input future, so cancelling it might disrupt other |
| 616 | # callers and B) concurrent futures can only be cancelled while they are |
| 617 | # in the queue, so cancellation cannot reliably bound our waiting time. |
| 618 | future_converted = convert_yielded(future) |
| 619 | result = _create_future() |
| 620 | chain_future(future_converted, result) |
| 621 | io_loop = IOLoop.current() |
| 622 | |
| 623 | def error_callback(future: Future) -> None: |
| 624 | try: |
| 625 | future.result() |
| 626 | except asyncio.CancelledError: |
| 627 | pass |
| 628 | except Exception as e: |
| 629 | if not isinstance(e, quiet_exceptions): |
| 630 | app_log.error( |
| 631 | "Exception in Future %r after timeout", future, exc_info=True |
| 632 | ) |
| 633 |
nothing calls this directly
no test coverage detected