-
Notifications
You must be signed in to change notification settings - Fork 34
Description
We have updated to use uvloop
some time ago and now that we use in the tests as well (#8014) we noticed that servicelib.aiohttp.monitor_slow_callbacks.enable
does not work as expected.
This is used in setup_diagnostics
to monitor incidents, whcih have an effect on the webserver healthcheck
https://github.com/itisfoundation/osparc-simcore/blob/315de3ae3c1474604208dae850e84e6bd1d642b7/services/web/server/src/simcore_service_webserver/diagnostics/plugin.py#L43-L49
So this prevents the healthcheck from working correctly!
Starting from Python 3.11, asyncio.Handle
is implemented in C, and it is no longer a pure Python object. That makes monkey-patching it (e.g., replacing its __call__
method or wrapping it for debugging) much harder or even impossible in the same way it was in earlier versions.
Also, uvloop
replaces the default event loop with its own C-based version, which further limits introspection and patchability.
aiodebug: log_slow_callbacks
no longer works out-of-the-box
In the past, you may have done something like:
import aiodebug.log_slow_callbacks
aiodebug.log_slow_callbacks.enable(0.05)
This worked by patching asyncio.Handle.__call__
— but as of Python 3.11 and with uvloop
, that method isn't patchable in Python anymore.
Workaround Options
1. Use asyncio.run
with a custom debug loop and no uvloop
If debugging is your goal, you might temporarily avoid uvloop
:
import asyncio
import aiodebug.log_slow_callbacks
def main():
aiodebug.log_slow_callbacks.enable(threshold=0.05)
asyncio.run(your_async_main())
if __name__ == '__main__':
main()
This only works if you're not using uvloop. With uvloop
, you're on a C implementation and Handle.__call__
is not patchable.
2. Use Python’s native asyncio
slow callback warnings
Set the debug mode and use the built-in warning mechanism:
import asyncio
async def main():
loop = asyncio.get_running_loop()
loop.set_debug(True)
# Optionally adjust warning threshold
loop.slow_callback_duration = 0.05
...
asyncio.run(main())
This works with Python ≥3.7 and provides basic slow-callback detection, even with uvloop
(as long as set_debug(True)
is respected — uvloop
supports it).
3. Patch using a custom event loop (if using pure asyncio)
If you’re not using uvloop
, you could monkey-patch Handle.__call__
, but with uvloop
, it's not viable because the loop implementation is in C.
Summary
Approach | Works with uvloop ? |
Works with Python ≥3.11 ? |
Notes |
---|---|---|---|
aiodebug.log_slow_callbacks |
❌ | ❌ | No longer patchable due to C impl |
Native loop.set_debug(True) |
✅ | ✅ | Safe and built-in |
Monkey-patch Handle.__call__ |
❌ (uvloop) / |
❌ (3.11+) | No longer viable |
Recommendation
Use native asyncio
slow callback logging:
async def main():
loop = asyncio.get_running_loop()
loop.set_debug(True)
loop.slow_callback_duration = 0.05
...