Skip to content

Concurrent Execution

Run multiple Claude Code prompts in parallel with concurrency control.

ConcurrentExecutor

ConcurrentExecutor(app_name, *, token=None, max_concurrency=None, wait_timeout=3600.0)

Manages concurrent execution of Claude Code prompts on Fly.io machines.

Each prompt is dispatched to its own Fly machine. All machines run in parallel via asyncio, and cleanup is guaranteed for every machine regardless of individual success or failure.

Parameters:

Name Type Description Default
app_name str

The Fly app to run machines in.

required
token str | None

Explicit Fly API token (falls back to FLY_API_TOKEN).

None
max_concurrency int | None

Maximum number of machines to run simultaneously. Use 0 or None for unlimited concurrency.

None
wait_timeout float

Max seconds to wait for each machine to exit.

3600.0

Example::

executor = ConcurrentExecutor("my-fly-app")
requests = [
    ExecutionRequest(config=MachineConfig(prompt="Fix bug in auth", ...)),
    ExecutionRequest(config=MachineConfig(prompt="Add tests for API", ...)),
]
batch = await executor.run_batch(requests)
for result in batch.results:
    print(result.tag, result.success)
Source code in flaude/executor.py
def __init__(
    self,
    app_name: str,
    *,
    token: str | None = None,
    max_concurrency: int | None = None,
    wait_timeout: float = 3600.0,
) -> None:
    self.app_name = app_name
    self.token = token
    self.max_concurrency = max_concurrency or 0
    self.wait_timeout = wait_timeout

    # Semaphore for concurrency limiting (created lazily per run_batch)
    self._semaphore: asyncio.Semaphore | None = None

run_batch async

run_batch(requests)

Execute multiple prompts concurrently, each on its own Fly machine.

All machines are launched in parallel (subject to max_concurrency). Each machine is guaranteed to be cleaned up regardless of individual success or failure. Results are returned in the same order as the input requests.

Parameters:

Name Type Description Default
requests Sequence[ExecutionRequest]

The execution requests to process.

required

Returns:

Name Type Description
A BatchResult

class:BatchResult with per-request results and summary counts.

Source code in flaude/executor.py
async def run_batch(
    self,
    requests: Sequence[ExecutionRequest],
) -> BatchResult:
    """Execute multiple prompts concurrently, each on its own Fly machine.

    All machines are launched in parallel (subject to *max_concurrency*).
    Each machine is guaranteed to be cleaned up regardless of individual
    success or failure. Results are returned in the same order as the
    input requests.

    Args:
        requests: The execution requests to process.

    Returns:
        A :class:`BatchResult` with per-request results and summary counts.
    """
    if not requests:
        return BatchResult(results=[], total=0, succeeded=0, failed=0)

    # Set up concurrency limiter if configured
    if self.max_concurrency > 0:
        self._semaphore = asyncio.Semaphore(self.max_concurrency)
    else:
        self._semaphore = None

    logger.info(
        "Starting batch of %d executions (max_concurrency=%s)",
        len(requests),
        self.max_concurrency or "unlimited",
    )

    # Launch all tasks concurrently via asyncio.gather.
    # return_exceptions=False because _execute_one never raises —
    # it catches all exceptions internally.
    tasks = [self._execute_one(req) for req in requests]
    results: list[ExecutionResult] = await asyncio.gather(*tasks)

    succeeded = sum(1 for r in results if r.success)
    failed = len(results) - succeeded

    logger.info(
        "Batch complete: %d/%d succeeded, %d failed",
        succeeded,
        len(results),
        failed,
    )

    return BatchResult(
        results=results,
        total=len(results),
        succeeded=succeeded,
        failed=failed,
    )

run_one async

run_one(config, *, name=None, tag='')

Convenience method to execute a single prompt.

Equivalent to calling :meth:run_batch with a single request.

Parameters:

Name Type Description Default
config MachineConfig

Machine configuration.

required
name str | None

Optional machine name.

None
tag str

Optional tag for result correlation.

''

Returns:

Name Type Description
An ExecutionResult

class:ExecutionResult for the single execution.

Source code in flaude/executor.py
async def run_one(
    self,
    config: MachineConfig,
    *,
    name: str | None = None,
    tag: str = "",
) -> ExecutionResult:
    """Convenience method to execute a single prompt.

    Equivalent to calling :meth:`run_batch` with a single request.

    Args:
        config: Machine configuration.
        name: Optional machine name.
        tag: Optional tag for result correlation.

    Returns:
        An :class:`ExecutionResult` for the single execution.
    """
    request = ExecutionRequest(config=config, name=name, tag=tag)
    batch = await self.run_batch([request])
    return batch.results[0]

ExecutionRequest dataclass

ExecutionRequest(config, name=None, tag='')

A single prompt execution request to be dispatched to a Fly machine.

Attributes:

Name Type Description
config MachineConfig

Machine configuration (includes prompt, repos, credentials).

name str | None

Optional human-readable name for the machine.

tag str

Optional user-defined tag for correlating results back to requests.

ExecutionResult dataclass

ExecutionResult(tag, run_result=None, error=None)

Result of a single execution within a batch.

Attributes:

Name Type Description
tag str

The tag from the corresponding :class:ExecutionRequest.

run_result RunResult | None

The :class:RunResult if execution completed (success or failure).

error Exception | None

The exception if the execution failed before producing a result.

success property

success

True if the execution completed with exit code 0.

BatchResult dataclass

BatchResult(results, total=0, succeeded=0, failed=0)

Aggregated results from a concurrent batch execution.

Attributes:

Name Type Description
results list[ExecutionResult]

Individual results in the same order as the input requests.

total int

Total number of executions.

succeeded int

Count of executions that completed with exit code 0.

failed int

Count of executions that completed with non-zero exit or errored.

all_succeeded property

all_succeeded

True if every execution in the batch completed with exit code 0.