LeasedExecutorManager

class LeasedExecutorManager(*, backend=ExecutorBackend.THREAD, max_pools, min_pools=1, units_per_pool=10, size_provider=None, check_interval=120.0, default_lease_seconds=300.0, lease_grace_seconds=15.0, workers_per_pool=4, name_prefix='leasepool', logger=None, process_logging=None, forward_process_logs=False, process_log_level=20, process_log_target_logger=None, clear_process_log_handlers=True, **executor_kwargs)[source]

Bases: object

Bounded async manager for leased Executor instances.

The manager supports ThreadPoolExecutor and ProcessPoolExecutor on Python 3.11. Python 3.14+ can add InterpreterPoolExecutor through the same backend hook.

Sizing rule:
desired executors =

max(min_pools, ceil(size_provider() / units_per_pool))

desired executors is capped at max_pools.

Init the LeasedExecutorManager.

Parameters:
  • max_pools (int) – Maximum number of executor pools to create.

  • backend (ExecutorBackend | str, optional) – The backend type for the executor. Defaults to ExecutorBackend.THREAD.

  • min_pools (int, optional) – Minimum number of executor pools to maintain. Defaults to 1.

  • units_per_pool (int, optional) – Number of units per pool. Defaults to 10.

  • size_provider (SizeProvider | None, optional) – Function to provide the size. Defaults to None.

  • check_interval (float, optional) – Interval for checking the executor status. Defaults to 120.0.

  • default_lease_seconds (float, optional) – Default lease duration in seconds. Defaults to 300.0.

  • lease_grace_seconds (float, optional) – Grace period for lease expiration in seconds. Defaults to 15.0.

  • workers_per_pool (int, optional) – Number of workers per pool. Defaults to 4.

  • name_prefix (str, optional) – Prefix for naming executor pools. Defaults to “leasepool”.

  • logger (logging.Logger | None, optional) – Logger instance for logging. Defaults to None.

  • process_logging (ProcessLoggingConfig | None, optional) – Configuration for process logging. Defaults to None.

  • forward_process_logs (bool, optional) – Whether to forward process logs. Defaults to False.

  • process_log_level (int | str, optional) – Logging level for process logs. Defaults to logging.INFO.

  • process_log_target_logger (logging.Logger | None, optional) – Target logger for process logs. Defaults to None.

  • clear_process_log_handlers (bool, optional) – Whether to clear process log handlers. Defaults to True.

  • executor_kwargs (Any)

Raises:
  • ValueError – If max_pools, min_pools, units_per_pool, or workers_per_pool are not positive integers.

  • ValueError – If default_lease_seconds, lease_grace_seconds, or check_interval are not finite durations.

  • ValueError – If min_pools is greater than max_pools.

  • ValueError – If process logging configuration is invalid.

  • ValueError – If process log forwarding is enabled for a non-process backend.

__init__(*, backend=ExecutorBackend.THREAD, max_pools, min_pools=1, units_per_pool=10, size_provider=None, check_interval=120.0, default_lease_seconds=300.0, lease_grace_seconds=15.0, workers_per_pool=4, name_prefix='leasepool', logger=None, process_logging=None, forward_process_logs=False, process_log_level=20, process_log_target_logger=None, clear_process_log_handlers=True, **executor_kwargs)[source]

Init the LeasedExecutorManager.

Parameters:
  • max_pools (int) – Maximum number of executor pools to create.

  • backend (ExecutorBackend | str, optional) – The backend type for the executor. Defaults to ExecutorBackend.THREAD.

  • min_pools (int, optional) – Minimum number of executor pools to maintain. Defaults to 1.

  • units_per_pool (int, optional) – Number of units per pool. Defaults to 10.

  • size_provider (SizeProvider | None, optional) – Function to provide the size. Defaults to None.

  • check_interval (float, optional) – Interval for checking the executor status. Defaults to 120.0.

  • default_lease_seconds (float, optional) – Default lease duration in seconds. Defaults to 300.0.

  • lease_grace_seconds (float, optional) – Grace period for lease expiration in seconds. Defaults to 15.0.

  • workers_per_pool (int, optional) – Number of workers per pool. Defaults to 4.

  • name_prefix (str, optional) – Prefix for naming executor pools. Defaults to “leasepool”.

  • logger (logging.Logger | None, optional) – Logger instance for logging. Defaults to None.

  • process_logging (ProcessLoggingConfig | None, optional) – Configuration for process logging. Defaults to None.

  • forward_process_logs (bool, optional) – Whether to forward process logs. Defaults to False.

  • process_log_level (int | str, optional) – Logging level for process logs. Defaults to logging.INFO.

  • process_log_target_logger (logging.Logger | None, optional) – Target logger for process logs. Defaults to None.

  • clear_process_log_handlers (bool, optional) – Whether to clear process log handlers. Defaults to True.

  • executor_kwargs (Any)

Raises:
  • ValueError – If max_pools, min_pools, units_per_pool, or workers_per_pool are not positive integers.

  • ValueError – If default_lease_seconds, lease_grace_seconds, or check_interval are not finite durations.

  • ValueError – If min_pools is greater than max_pools.

  • ValueError – If process logging configuration is invalid.

  • ValueError – If process log forwarding is enabled for a non-process backend.

property backend: ExecutorBackend
async start()[source]

Start the LeasedExecutorManager.

Return type:

None

async stop()[source]

Stop the LeasedExecutorManager.

Return type:

None

async acquire(*, lease_seconds=None, owner=None, wait=True, timeout=None)[source]

Acquire an executor lease.

Parameters:
  • lease_seconds (float | None, optional) – The duration of the lease in seconds. Defaults to None.

  • owner (str | None, optional) – The owner of the lease. Defaults to None.

  • wait (bool, optional) – Whether to wait for an available executor. Defaults to True.

  • timeout (float | None, optional) – The maximum time to wait for an available executor in seconds. Defaults to None.

Raises:
Returns:

The acquired executor lease.

Return type:

ExecutorLease

async release(lease_id)[source]

Release an executor lease.

If submitted futures are still running, the lease enters a draining state. The executor is returned to the pool only after all tracked futures finish.

Return type:

None

Parameters:

lease_id (str)

notify_scale_changed()[source]

Inform the checker that the size signal changed.

Return type:

None

desired_executor_count()[source]
Return type:

int

property available_count: int
property leased_count: int
property total_count: int
stats()[source]

Get statistics about the executor manager.

Returns:

A dictionary containing statistics about the executor manager.

Return type:

dict[str, Any]

Manual summary

Constructor

LeasedExecutorManager(
    *,
    backend="thread",
    max_pools,
    min_pools=1,
    units_per_pool=10,
    size_provider=None,
    check_interval=120.0,
    default_lease_seconds=300.0,
    lease_grace_seconds=15.0,
    workers_per_pool=4,
    name_prefix="leasepool",
    logger=None,
    process_logging=None,
    forward_process_logs=False,
    process_log_level=logging.INFO,
    process_log_target_logger=None,
    clear_process_log_handlers=True,
    **executor_kwargs,
)

Lifecycle

await manager.start()

Start the manager, create the minimum/desired pool count, and start the checker task. After the manager has started, this method must be called from the owning event loop. Calling it from another event loop raises RuntimeError.

await manager.stop()

Stop the checker task, clear available and leased pools, shut down owned executors, and stop process log forwarding if it is running. Calling stop() before start() is safe and remains a no-op.

Acquiring and releasing

await manager.acquire(lease_seconds=None, owner=None, wait=True, timeout=None)

Borrow an executor through an ExecutorLease.

await manager.release(lease_id)

Return a lease manually. Most users call await lease.release() or use the lease as an async context manager instead.

Lease draining

If work was submitted through lease.executor.submit(), releasing the lease marks it as released and rejects new submissions, but the executor is not returned to the available pool until submitted futures finish.

This prevents work submitted under one lease from overlapping with work submitted under a later lease on the same executor.

Broken executor handling

If an executor becomes broken, the manager retires it, removes it from active leases, shuts it down, and creates replacement capacity when needed.

Shutdown triggered from future callbacks is deferred out of the callback context to avoid deadlocks or hangs in backend-owned callback threads.

Sizing and diagnostics

manager.notify_scale_changed()

Wake the checker after the adaptive size signal changes.

manager.desired_executor_count()

Return the current adaptive target.

manager.stats()

Return a diagnostic snapshot dictionary.

Common properties

manager.backend

Backend enum.

manager.available_count

Number of idle executor pools.

manager.leased_count

Number of currently leased executor pools.

manager.total_count

Available plus leased executor pools.