freezegun
freezegun copied to clipboard
calling (and awaiting) asyncio.sleep seems to cause an infinite hang on 1.1.0
I upgraded a project to the latest version of freezegun recently and a test which relied on an interaction which happened in the background started failing. I tracked it down to being due to any call to await asyncio.sleep(..)
to hang forever. Perhaps the internal mechanism used in asyncio is sensitive to the way freezegun patches time modules?
I think this may be related to: https://github.com/spulec/freezegun/issues/290 but I am not sure since this works fine on version 1.0.0 which was released after that issue was created. Additionally I wanted to submit a simple example to reproduce the problem. If it's indeed the same issue, my apologies, I am happy to contribute over there instead.
My python version is: 3.9.1
Here's a proof of concept (t.py):
import signal
import sys
import asyncio
import freezegun
TIMEOUT = 5
def timeout(sig, frame):
print(f"exiting due to {TIMEOUT}s timeout")
sys.exit(1)
async def main():
print("Normal asyncio.sleep(1)")
await asyncio.sleep(1)
print("Done!")
with freezegun.freeze_time("2022-01-01"):
print("Frozen asyncio.sleep(1)")
await asyncio.sleep(1)
print("Done! (success)")
if __name__ == "__main__":
signal.signal(signal.SIGALRM, timeout)
signal.alarm(TIMEOUT)
asyncio.run(main())
Running this on 1.1.0 causes the signal handler to execute, since the main method never gets passed the asyncio.sleep(1)
call within the freeze_time context.
$ venv/bin/pip install freezegun==1.1.0 && venv/bin/python t.py
Requirement already satisfied: freezegun==1.1.0 in ./venv/lib/python3.9/site-packages (1.1.0)
Requirement already satisfied: python-dateutil>=2.7 in ./venv/lib/python3.9/site-packages (from freezegun==1.1.0) (2.8.2)
Requirement already satisfied: six>=1.5 in ./venv/lib/python3.9/site-packages (from python-dateutil>=2.7->freezegun==1.1.0) (1.16.0)
WARNING: You are using pip version 20.3.3; however, version 21.3.1 is available.
You should consider upgrading via the '/Users/ses/w/freezegun-async-sleep-poc/venv/bin/python -m pip install --upgrade pip' command.
Normal asyncio.sleep(1)
Done!
Frozen asyncio.sleep(1)
exiting due to 5s timeout
Downgrading to 1.0.0 seems to "fix" this.
$ venv/bin/pip install freezegun==1.0.0 && venv/bin/python t.py
Collecting freezegun==1.0.0
Using cached freezegun-1.0.0-py2.py3-none-any.whl (14 kB)
Requirement already satisfied: python-dateutil>=2.7 in ./venv/lib/python3.9/site-packages (from freezegun==1.0.0) (2.8.2)
Requirement already satisfied: six>=1.5 in ./venv/lib/python3.9/site-packages (from python-dateutil>=2.7->freezegun==1.0.0) (1.16.0)
Installing collected packages: freezegun
Attempting uninstall: freezegun
Found existing installation: freezegun 1.1.0
Uninstalling freezegun-1.1.0:
Successfully uninstalled freezegun-1.1.0
Successfully installed freezegun-1.0.0
WARNING: You are using pip version 20.3.3; however, version 21.3.1 is available.
You should consider upgrading via the '/Users/ses/w/freezegun-async-sleep-poc/venv/bin/python -m pip install --upgrade pip' command.
Normal asyncio.sleep(1)
Done!
Frozen asyncio.sleep(1)
Done! (success)
I was hopeful that, after I raised #290, time.monotonic
being patched would mean that await asyncio.sleep(...)
would be instant, but it seems, since that was introduced in 1.1.0, that instead this has caused this issue, which we are also seeing if we try to upgrade beyond 1.0.0.
The issue is relatively simple in nature: within the event loop, time never advances, so the loop does not believe it ever reaches the time at which the timer, added to end the sleep, should fire.