Install & Compatibility
Where this runs
tested against v2.3.0 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.95 runs
installs and imports cleanly · install 0.0s · import 0.220s · 18.1MB
glibcpy 3.10–3.95 runs
installs and imports cleanly · install 1.6s · import 0.186s · 19MB
16MB installed
● package 16MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
alru_cache
✓ from async_lru import alru_cache
✗ from functools import lru_cache
Using `functools.lru_cache` on an `async def` function will cache the coroutine object itself, not its awaited result, leading to `RuntimeError: cannot reuse already awaited coroutine` on subsequent awaits. `async-lru` provides `alru_cache` for correct async function caching.
This quickstart demonstrates basic usage of the `alru_cache` decorator with `maxsize`, `ttl` (time-to-live), and `jitter` parameters. It shows how to inspect cache statistics using `cache_info()`, check for cache presence with `cache_contains()`, and explicitly close the cache with `cache_close()` to release resources. Note that `aiohttp` is used for demonstration purposes of an actual async network call.
import asyncio
import aiohttp
from async_lru import alru_cache
@alru_cache(maxsize=32, ttl=10, jitter=2)
async def get_pep(num):
"""Fetches a PEP from python.org, caches the result."""
resource = f'http://www.python.org/dev/peps/pep-{num:04d}/'
print(f"Fetching PEP {num}...")
async with aiohttp.ClientSession() as session:
try:
async with session.get(resource) as s:
if s.status == 200:
return await s.text()
return f'Not Found (Status: {s.status})'
except aiohttp.ClientError as e:
return f'Network Error: {e}'
async def main():
print("\n--- First round (misses) ---")
for n in 8, 290, 308, 320:
pep = await get_pep(n)
print(f"PEP {n}: {len(pep) if pep else 'Error'} characters")
print("\n--- Second round (hits) ---")
for n in 8, 218, 320:
pep = await get_pep(n)
print(f"PEP {n}: {len(pep) if pep else 'Error'} characters")
print("\n--- Cache Info ---")
print(get_pep.cache_info())
print("\n--- Checking cache_contains ---")
print(f"Cache contains PEP 8: {get_pep.cache_contains(8)}")
print(f"Cache contains PEP 9991: {get_pep.cache_contains(9991)}")
# Simulate passage of time for TTL
print("\n--- Waiting for TTL expiration (10 seconds) ---")
await asyncio.sleep(10) # Wait for TTL
print("\n--- After TTL: PEP 8 (should re-fetch) ---")
pep = await get_pep(8)
print(f"PEP 8: {len(pep) if pep else 'Error'} characters")
print(get_pep.cache_info())
# Closing is optional but highly recommended to release resources
await get_pep.cache_close()
if __name__ == '__main__':
# This example requires aiohttp for network requests
# If aiohttp is not installed, the example will still run but 'get_pep' will fail.
# pip install aiohttp
try:
asyncio.run(main())
except RuntimeError as e:
print(f"Caught a runtime error: {e}. This might happen if the event loop is already running.")
Debug
Known issues
breakingCross-event loop cache access behavior changed significantly between v2.2.0 and v2.3.0. Prior to v2.3.0 (from v2.2.0 onwards), attempting to use an `alru_cache` instance with a different event loop than where it was first called would raise a `RuntimeError` ('alru_cache is not safe to use across event loops').fixFor versions before 2.3.0, ensure a cache instance is strictly used with a single event loop, or create separate cache instances per loop. If you need cross-loop usage, upgrade to v2.3.0+ and be aware of the new auto-reset behavior.
affects: >=2.2.0, <2.3.0
gotchaAs of v2.3.0, cross-event loop cache access no longer raises a `RuntimeError` but instead triggers an auto-reset and rebind to the current event loop, emitting an `AlruCacheLoopResetWarning`. While this prevents hard crashes, it means the cache effectively clears and reinitializes when the event loop changes, potentially losing cached data.fixIf multi-event loop usage is intentional, be mindful that the cache will reset. For persistent caching across different loops or threads, consider explicit cache management (e.g., using `threading.local` for per-thread/loop caches) or a shared, thread-safe external caching mechanism.
affects: >=2.3.0
gotchaIt is highly recommended to explicitly close `alru_cache` instances using `cache_close()`, especially when using `ttl` (time-to-live). Failing to close the cache can lead to resource leaks (e.g., lingering asyncio tasks or timers) that might prevent your application from shutting down cleanly or lead to unexpected behavior.fixAlways call `await func.cache_close()` on your cached functions when they are no longer needed, typically during application shutdown or when disposing of objects that hold cached methods.
affects: All versions
gotchaWhen using `ttl` (time-to-live) for cache entries, many entries expiring simultaneously can lead to a 'thundering herd' problem, where many clients try to recompute the same value at once. This can negate the benefits of caching and strain backend resources.fixUtilize the `jitter` parameter (introduced in v2.2.0) with `ttl` to randomize expiration times. For example, `@alru_cache(ttl=3600, jitter=1800)` will spread expirations over a 1.5-hour window around the 1-hour TTL.
affects: All versions with `ttl`
breakingThe script failed because a required dependency, 'aiohttp', was not found. This indicates an incomplete or incorrect environment setup for running the script.fixEnsure that 'aiohttp' is installed in the environment where the script is being executed (e.g., by adding `pip install aiohttp` to the setup steps).
affects: All versions where 'aiohttp' is required by the tested script but is not installed.
breakingThe application failed due to a missing 'aiohttp' dependency, resulting in a ModuleNotFoundError. This typically means the package was not included in the environment setup or installation steps.fixEnsure 'aiohttp' is listed as a dependency and properly installed in the environment where the application is run (e.g., via `pip install aiohttp`). If using a `requirements.txt` file, make sure 'aiohttp' is present there.
affects: All versions (where 'aiohttp' is a dependency)
Errors
Common errors & fixes
ModuleNotFoundError: No module named 'async_lru'
The 'async_lru' module is not installed in the Python environment.
fixInstall the module using pip: 'pip install async-lru'.
ImportError: cannot import name 'alru_cache' from 'async_lru'
The 'alru_cache' function is not found in the 'async_lru' module, possibly due to an incorrect import statement.
fixEnsure the correct import statement: 'from async_lru import alru_cache'.
RuntimeError: alru_cache is not safe to use across event loops: this cache instance was first used with a different event loop. Use separate cache instances per event loop.
The 'alru_cache' instance is being accessed from a different event loop than the one it was first used with.
fixCreate separate cache instances for each event loop to avoid cross-event loop usage.
TypeError: alru_cache() got an unexpected keyword argument 'ttl'
The 'ttl' parameter is not recognized, possibly due to using an outdated version of 'async-lru'.
fixUpdate 'async-lru' to the latest version using pip: 'pip install --upgrade async-lru'.
AttributeError: 'function' object has no attribute 'cache_invalidate'
The 'cache_invalidate' method is being called on a function that is not decorated with 'alru_cache'.
fixEnsure the function is decorated with '@alru_cache' before calling 'cache_invalidate'.
Upgrade
Version history
2.3.0latest on PyPI · released Mar 19, 2026
Audit
Dependencies
No dependency data recorded yet.