Skip to content

Executors

aereo.executors

Executor abstraction for running extraction tasks.

LambdaExecutor

LambdaExecutor(
    function_name,
    staging_bucket,
    storage=None,
    failure_mode=_STRICT_MODE,
    endpoint_url=None,
    max_concurrent_invokes=10,
    invoke_timeout=900,
)

Execute extraction tasks remotely via AWS Lambda.

Each :class:ExtractionTask is serialized, staged to S3, and dispatched as a separate Lambda invocation. The Lambda handler is expected to deserialize the task, run the extraction, upload the results, and return a JSON payload with a manifest_uri key.

Because boto3 is an optional dependency, it is imported lazily inside :meth:__init__. Install it with pip install boto3 before using this executor.

Create a new Lambda executor.

PARAMETER DESCRIPTION
function_name

AWS Lambda function name or ARN.

TYPE: str

staging_bucket

S3 bucket used to stage serialized tasks.

TYPE: str

storage

Optional storage backend used to load result manifests. When None, a backend is resolved from each manifest URI.

TYPE: StorageBackend | None DEFAULT: None

failure_mode

"strict" aborts on the first failed task; "best_effort" skips failed tasks and returns successful ones.

TYPE: Literal['strict', 'best_effort'] DEFAULT: _STRICT_MODE

endpoint_url

Optional boto3 endpoint URL (e.g. http://localhost:4566 for LocalStack emulation).

TYPE: str | None DEFAULT: None

max_concurrent_invokes

Maximum number of concurrent Lambda invocations.

TYPE: int DEFAULT: 10

invoke_timeout

Read timeout in seconds for the boto3 Lambda client.

TYPE: int DEFAULT: 900

RAISES DESCRIPTION
ImportError

If boto3 is not installed.

Source code in components/aereo/executors/_lambda.py
def __init__(
    self,
    function_name: str,
    staging_bucket: str,
    storage: StorageBackend | None = None,
    failure_mode: Literal["strict", "best_effort"] = _STRICT_MODE,
    endpoint_url: str | None = None,
    max_concurrent_invokes: int = 10,
    invoke_timeout: int = 900,
) -> None:
    """Create a new Lambda executor.

    Args:
        function_name: AWS Lambda function name or ARN.
        staging_bucket: S3 bucket used to stage serialized tasks.
        storage: Optional storage backend used to load result manifests.
            When ``None``, a backend is resolved from each manifest URI.
        failure_mode: ``"strict"`` aborts on the first failed task;
            ``"best_effort"`` skips failed tasks and returns successful ones.
        endpoint_url: Optional boto3 endpoint URL (e.g. ``http://localhost:4566``
            for LocalStack emulation).
        max_concurrent_invokes: Maximum number of concurrent Lambda invocations.
        invoke_timeout: Read timeout in seconds for the boto3 Lambda client.

    Raises:
        ImportError: If ``boto3`` is not installed.
    """
    self.function_name = function_name
    self.staging_bucket = staging_bucket
    self.storage = storage
    self.failure_mode = failure_mode
    self.endpoint_url = endpoint_url
    self.max_concurrent_invokes = max_concurrent_invokes
    self._invoke_timeout = invoke_timeout

    self._serializer = _TaskSerializer()
    self._staging = _CloudTaskStaging(
        bucket=staging_bucket, endpoint_url=endpoint_url
    )

    try:
        import boto3  # pyright: ignore[reportMissingImports]
        from botocore.config import Config  # pyright: ignore[reportMissingImports]
    except ImportError as exc:
        raise ImportError(
            "boto3 is required for LambdaExecutor. "
            "Install it with: pip install boto3"
        ) from exc

    self._lambda_client = boto3.client(
        "lambda",
        endpoint_url=endpoint_url,
        config=Config(
            read_timeout=invoke_timeout,
            retries={"max_attempts": 3, "mode": "adaptive"},
        ),
    )

RetryableLambdaError

Bases: RuntimeError

Raised when a Lambda invocation fails with a retryable error.

Executor

Bases: Protocol

Protocol for pluggable task executors.

An executor turns a sequence of :class:ExtractionTask objects into a single validated artifact GeoDataFrame.

LocalExecutor

LocalExecutor(
    workers=1,
    failure_mode=_STRICT_MODE,
    cache=None,
    use_threads=False,
)

Execute extraction tasks locally.

Wraps :func:aereo.execution.run_task with optional caching, failure handling, and local parallelism through joblib.

By default joblib's loky backend is used for process-based parallelism. loky starts clean interpreter processes, which avoids the fork-after-read deadlock that happens when worker processes inherit netCDF/HDF5 state from the parent.

Create a new LocalExecutor.

PARAMETER DESCRIPTION
workers

Maximum number of parallel workers. None or 1 runs tasks sequentially in the current process. >1 dispatches tasks through a joblib pool. If -1 is passed, the number of workers is set to the number of CPUs in the system.

TYPE: int | None DEFAULT: 1

failure_mode

"strict" aborts on the first failed task; "best_effort" skips failed tasks and returns successful ones.

TYPE: Literal['strict', 'best_effort'] DEFAULT: _STRICT_MODE

cache

Optional per-task artifact catalog cache.

TYPE: TaskResultCache | None DEFAULT: None

use_threads

When True and workers > 1, use joblib's threading backend instead of loky.

TYPE: bool DEFAULT: False

Source code in components/aereo/executors/core.py
def __init__(
    self,
    workers: int | None = 1,
    failure_mode: Literal["strict", "best_effort"] = _STRICT_MODE,
    cache: TaskResultCache | None = None,
    use_threads: bool = False,
) -> None:
    """Create a new LocalExecutor.

    Args:
        workers: Maximum number of parallel workers. ``None`` or ``1`` runs
            tasks sequentially in the current process. ``>1`` dispatches
            tasks through a joblib pool. If -1 is passed, the number of
            workers is set to the number of CPUs in the system.
        failure_mode: ``"strict"`` aborts on the first failed task;
            ``"best_effort"`` skips failed tasks and returns successful ones.
        cache: Optional per-task artifact catalog cache.
        use_threads: When ``True`` and *workers* > 1, use joblib's
            ``threading`` backend instead of ``loky``.
    """
    self.workers = workers
    if self.workers == -1:
        import multiprocessing

        self.workers = multiprocessing.cpu_count()
    self.failure_mode = failure_mode
    self.cache = cache
    self.use_threads = use_threads

shutdown

shutdown(_wait=True)

No-op for API compatibility.

joblib's loky backend already reuses and cleans up its worker pool automatically.

Source code in components/aereo/executors/core.py
def shutdown(self, _wait: bool = True) -> None:
    """No-op for API compatibility.

    ``joblib``'s ``loky`` backend already reuses and cleans up its worker
    pool automatically.
    """
    return None