-
Notifications
You must be signed in to change notification settings - Fork 32
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
...