FAQ === Is leasepool a task queue? -------------------------- No. leasepool manages local executor capacity inside one Python process. It does not provide distributed workers, persistence, retries across machines, scheduling, or broker integration. Should I use threads or processes? ---------------------------------- Use threads for blocking I/O and synchronous libraries. Use processes for CPU-heavy Python work when functions and data are picklable. Can I submit async functions? ----------------------------- No. leasepool is designed for synchronous callables that need to run outside the event loop. Async functions should usually be awaited directly. Is max_pools global? -------------------- No. ``max_pools`` applies to one ``LeasedExecutorManager`` instance. Separate thread and process managers each enforce their own limits. What happens if every pool is leased? ------------------------------------- ``manager.acquire()`` waits by default. Pass ``timeout=...`` to bound the wait or ``wait=False`` to raise ``LeaseUnavailableError`` immediately. What happens after a lease expires? ----------------------------------- After ``lease_seconds + lease_grace_seconds``, new submissions through that lease raise ``LeaseExpiredError``. Use context managers and realistic lease durations to avoid accidental expiry. Can I use InterpreterPoolExecutor on Python 3.11? ------------------------------------------------- No. The interpreter backend is reserved for Python 3.14+. Why do worker-process logs not appear in my app logs? ----------------------------------------------------- Process workers run in child processes. Enable ``ProcessLoggingConfig`` or ``forward_process_logs=True`` when using the process backend if you want worker log records forwarded to a parent-process logger. Can I pass executor-specific options? ------------------------------------- Yes. Extra keyword arguments passed to ``LeasedExecutorManager`` are forwarded to the underlying executor constructor. For example, process managers can receive ``initializer``, ``initargs``, ``mp_context``, or ``max_tasks_per_child``. What happens if I release a lease while submitted work is still running? ----------------------------------------------------------------------- The lease enters a draining state. New submissions through that lease are rejected, and the executor is returned to the pool only after submitted futures finish. Does lease expiry kill already-running work? -------------------------------------------- No. Lease expiry prevents new submissions after hard expiry and may shut down the underlying executor with normal executor semantics. Already-running Python code follows the behavior of the selected backend. Can I call WorkGrinder from another event loop? ----------------------------------------------- Call async WorkGrinder methods only from the event loop that started the grinder. Use ``submit_from_thread()`` and ``stats_from_thread()`` from another OS thread. Why does manager.acquire() raise "owning event loop"? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A started manager is bound to the event loop that started it. Use it from that loop, or schedule work onto that loop through an application-level thread-safe boundary. Why does submit_from_thread() fail inside async code? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``submit_from_thread()`` is only for non-owner OS threads. Inside async code on the grinder's owning loop, use ``await grinder.submit(...)`` or ``await grinder.enqueue(...)``.