1
0

asyncio.wait_for() is too buggy. use util.wait_for2() instead

wasted some time because asyncio.wait_for() was suppressing cancellations. [0][1][2]
deja vu... [3]

Looks like this is finally getting fixed in cpython 3.12 [4]
So far away...
In attempt to avoid encountering this again, let's try using
asyncio.timeout in 3.11, which is how upstream reimplemented wait_for in 3.12 [4], and
aiorpcx.timeout_after in 3.8-3.10.

[0] https://github.com/python/cpython/issues/86296
[1] https://bugs.python.org/issue42130
[2] https://bugs.python.org/issue45098
[3] https://github.com/kyuupichan/aiorpcX/issues/44
[4] https://github.com/python/cpython/pull/98518
This commit is contained in:
SomberNight
2023-08-04 17:59:47 +00:00
parent 20f4d44f09
commit d51f00e2a3
8 changed files with 63 additions and 31 deletions

View File

@@ -24,7 +24,7 @@ import binascii
import os, sys, re, json
from collections import defaultdict, OrderedDict
from typing import (NamedTuple, Union, TYPE_CHECKING, Tuple, Optional, Callable, Any,
Sequence, Dict, Generic, TypeVar, List, Iterable, Set)
Sequence, Dict, Generic, TypeVar, List, Iterable, Set, Awaitable)
from datetime import datetime
import decimal
from decimal import Decimal
@@ -1371,6 +1371,36 @@ aiorpcx.curio._set_task_deadline = _aiorpcx_monkeypatched_set_task_deadline
aiorpcx.curio._unset_task_deadline = _aiorpcx_monkeypatched_unset_task_deadline
async def wait_for2(fut: Awaitable, timeout: Union[int, float, None]):
"""Replacement for asyncio.wait_for,
due to bugs: https://bugs.python.org/issue42130 and https://github.com/python/cpython/issues/86296 ,
which are only fixed in python 3.12+.
"""
if sys.version_info[:3] >= (3, 12):
return await asyncio.wait_for(fut, timeout)
else:
async with async_timeout(timeout):
return await asyncio.ensure_future(fut, loop=get_running_loop())
if hasattr(asyncio, 'timeout'): # python 3.11+
async_timeout = asyncio.timeout
else:
class TimeoutAfterAsynciolike(aiorpcx.curio.TimeoutAfter):
async def __aexit__(self, exc_type, exc_value, traceback):
try:
await super().__aexit__(exc_type, exc_value, traceback)
except (aiorpcx.TaskTimeout, aiorpcx.UncaughtTimeoutError):
raise asyncio.TimeoutError from None
except aiorpcx.TimeoutCancellationError:
raise asyncio.CancelledError from None
def async_timeout(delay: Union[int, float, None]):
if delay is None:
return nullcontext()
return TimeoutAfterAsynciolike(delay)
class NetworkJobOnDefaultServer(Logger, ABC):
"""An abstract base class for a job that runs on the main network
interface. Every time the main interface changes, the job is