Utility to detect blocking calls in the async event loop
Blockbuster is a Python package designed to detect and prevent blocking calls within an asynchronous event loop. It's particularly useful during testing to ensure asynchronous code doesn't inadvertently perform blocking operations, which can cause performance bottlenecks. It works by monkey-patching common blocking functions and raising a `BlockingError` if called within an `asyncio` event loop. It currently only detects `asyncio` event loops and is tested with CPython.
Warnings
- breaking Breaking changes, such as new rules, may be introduced between minor versions. It is recommended to constrain the Blockbuster version on the minor version (e.g., `blockbuster>=1.5.0,<1.6`).
- gotcha Blockbuster currently only detects `asyncio` event loops. It does not provide detection for other asynchronous frameworks.
- gotcha Blockbuster is primarily tested with CPython. While it might work with other Python implementations, its functionality relies on the ability to monkey-patch functions with `setattr`, which may not be consistently available or behave identically across all interpreters.
- gotcha Blockbuster may not detect blocking calls made by third-party libraries that wrap C libraries instead of using standard Python framework methods for I/O.
Install
-
pip install blockbuster
Imports
- blockbuster_ctx
from blockbuster import blockbuster_ctx
- BlockingError
from blockbuster import BlockingError
Quickstart
import asyncio
import time
from blockbuster import blockbuster_ctx, BlockingError
async def main():
print("Running async task with blockbuster (should fail on time.sleep)...")
try:
with blockbuster_ctx():
# This is a blocking call and should raise BlockingError
time.sleep(0.1)
print("This line should not be reached if blocking call is detected.")
except BlockingError as e:
print(f"Caught expected BlockingError: {e}")
except Exception as e:
print(f"Caught unexpected error: {e}")
print("\nRunning async task without blockbuster (should complete)...")
try:
# This will complete without error
time.sleep(0.1)
print("Blocking call completed without blockbuster activated.")
except BlockingError as e:
print(f"Caught BlockingError (unexpected): {e}")
if __name__ == "__main__":
asyncio.run(main())