Error handling¶
leasepool exceptions¶
LeasePoolErrorBase exception for all leasepool-specific errors.
LeasePoolNotStartedErrorRaised when acquiring from a manager that has not been started.
LeaseUnavailableErrorRaised when
wait=Falseand no executor is available.LeaseExpiredErrorRaised when submitting through a released or expired lease.
UnsupportedBackendErrorRaised when requesting a backend that is not available on the current Python version.
Acquire before start¶
from leasepool import LeasePoolNotStartedError
try:
await manager.acquire()
except LeasePoolNotStartedError:
...
No capacity available¶
Use wait=False when you want to fail fast instead of waiting:
from leasepool import LeaseUnavailableError
try:
lease = await manager.acquire(wait=False)
except LeaseUnavailableError:
# Return HTTP 503, retry later, or enqueue elsewhere.
...
Use timeout when you are willing to wait for bounded time:
try:
lease = await manager.acquire(timeout=2.0)
except TimeoutError:
...
Expired leases¶
After hard expiry, new submissions through a lease raise LeaseExpiredError.
examples/06_lease_expiry_and_revocation.py¶
"""
Lease expiry and revocation.
A lease has:
- soft expiry: lease_seconds
- hard expiry: lease_seconds + lease_grace_seconds
After hard expiry, new submissions through that lease are rejected.
"""
from __future__ import annotations
import asyncio
from leasepool import LeasedExecutorManager, LeaseExpiredError
def echo(value: str) -> str:
return value
async def main() -> None:
manager = LeasedExecutorManager(
backend="thread",
max_pools=1,
min_pools=1,
workers_per_pool=1,
lease_grace_seconds=0.1,
check_interval=60,
)
await manager.start()
try:
lease = await manager.acquire(
owner="expiry-demo",
lease_seconds=0.1,
)
print("Lease ID:", lease.lease_id)
print("Soft expires at:", lease.soft_expires_at)
print("Hard expires at:", lease.hard_expires_at)
print("Before expiry:", await lease.run(echo, "ok"))
await asyncio.sleep(0.25)
try:
lease.executor.submit(echo, "too late")
except LeaseExpiredError as exc:
print("Submit after hard expiry was rejected:", exc)
print("Manager stats after expiry handling:", manager.stats())
finally:
await manager.stop()
if __name__ == "__main__":
asyncio.run(main())
Full exception example¶
examples/11_error_handling.py¶
"""
Common error handling patterns.
This example demonstrates the library exceptions users are most likely to handle.
"""
from __future__ import annotations
import asyncio
from leasepool import (
LeasedExecutorManager,
LeaseExpiredError,
LeasePoolNotStartedError,
LeaseUnavailableError,
)
def echo(value: str) -> str:
return value
async def main() -> None:
manager = LeasedExecutorManager(
backend="thread",
max_pools=1,
min_pools=1,
lease_grace_seconds=0.05,
)
try:
await manager.acquire()
except LeasePoolNotStartedError as exc:
print("Acquire before start failed:", exc)
await manager.start()
try:
first = await manager.acquire(owner="first")
try:
await manager.acquire(owner="second", wait=False)
except LeaseUnavailableError as exc:
print("No lease available:", exc)
await first.release()
expiring = await manager.acquire(owner="expiring", lease_seconds=0.05)
executor = expiring.executor
await asyncio.sleep(0.15)
try:
executor.submit(echo, "too late")
except LeaseExpiredError as exc:
print("Lease expired:", exc)
finally:
await manager.stop()
if __name__ == "__main__":
asyncio.run(main())