# AWS Batch **Protocol:** REST JSON **Endpoint:** `http://localhost:4566/v1/...` Floci Batch implements the AWS Batch control plane for local integration tests. It supports queue and job-definition metadata, immediate job completion for fast contract tests, Docker-backed execution when enabled, CloudFormation resource provisioning, and EventBridge rule targets with `BatchParameters`. ## Supported Operations | Operation | Endpoint | Description | |---|---|---| | `CreateComputeEnvironment` | `POST /v1/createcomputeenvironment` | Store a local compute environment and return its ARN | | `DescribeComputeEnvironments` | `POST /v1/describecomputeenvironments` | Describe all or selected compute environments | | `UpdateComputeEnvironment` | `POST /v1/updatecomputeenvironment` | Update a compute environment's state, service role, and compute resources | | `DeleteComputeEnvironment` | `POST /v1/deletecomputeenvironment` | Delete a `DISABLED` compute environment not referenced by any job queue; deleting a missing one is a no-op | | `CreateJobQueue` | `POST /v1/createjobqueue` | Store a local job queue attached to compute environments | | `UpdateJobQueue` | `POST /v1/updatejobqueue` | Update a job queue's state, priority, and compute environment order | | `DeleteJobQueue` | `POST /v1/deletejobqueue` | Delete a `DISABLED` job queue; deleting a missing queue is a no-op | | `DescribeJobQueues` | `POST /v1/describejobqueues` | Describe all or selected job queues | | `RegisterJobDefinition` | `POST /v1/registerjobdefinition` | Register a revisioned `container` or `multinode` job definition | | `DeregisterJobDefinition` | `POST /v1/deregisterjobdefinition` | Mark a job definition revision inactive | | `DescribeJobDefinitions` | `POST /v1/describejobdefinitions` | List job definitions by name, ARN, revision, and status | | `SubmitJob` | `POST /v1/submitjob` | Submit a local Batch job | | `CancelJob` | `POST /v1/canceljob` | Cancel a job that has not started running | | `TerminateJob` | `POST /v1/terminatejob` | Terminate a nonterminal job and stop its running container or nodes | | `DescribeJobs` | `POST /v1/describejobs` | Describe jobs by job ID | | `ListJobs` | `POST /v1/listjobs` | List jobs by queue, status, AWS `filters`, and pagination | ## Runner Modes Batch uses `floci.services.batch.runner-mode`. | Value | Behavior | |---|---| | `immediate` | Default. `SubmitJob` persists the job, records lifecycle timestamps, creates one successful attempt, and returns after the job is `SUCCEEDED`. | | `docker` | Starts one Docker container per attempt from the job-definition image, passes resolved command and environment values, applies `MEMORY` resource requirements as Docker memory limits, captures a CloudWatch Logs stream name, and sets `SUCCEEDED` or `FAILED` from the container exit code. Timed-out jobs fail without retry, matching AWS Batch timeout behavior. | `process` mode is not implemented. ## Submit Behavior Supported `SubmitJob` fields: - `jobName` - `jobDefinition` - `jobQueue` - `parameters` - `containerOverrides.command` - `containerOverrides.environment` - `arrayProperties.size` (array jobs) - `nodeOverrides.numNodes`, `nodeOverrides.nodePropertyOverrides` (multi-node parallel jobs) - `timeout.attemptDurationSeconds` - `retryStrategy.attempts` - `tags` `containerOverrides.command` replaces the job-definition command. Command entries like `Ref::inputKey` are resolved from the merged parameter map before execution. Submit-time environment overrides merge over job-definition environment variables. `dependsOn` (job dependencies) is not supported. Jobs move through these local statuses: ```text SUBMITTED -> PENDING -> RUNNABLE -> STARTING -> RUNNING -> SUCCEEDED|FAILED ``` Driving every immediate-mode job through `PENDING` is a local simplification for tests. AWS may skip that state when there are no dependency or capacity waits. ## Job Control `CancelJob` accepts jobs in `SUBMITTED`, `PENDING`, or `RUNNABLE` and moves them to `FAILED` with the requested reason. Jobs that already reached `STARTING` or `RUNNING` are left unchanged, matching AWS behavior. `TerminateJob` moves any nonterminal job to `FAILED`; in Docker mode it also stops and removes the running container. Both operations are idempotent for terminal jobs and require `jobId` and `reason`. For an array parent, job control cascades to its children. Cancellation affects only children that have not started, while termination also stops running children. Terminating an MNP job stops every running node container. The stored terminal reason wins over a concurrent container exit, so the background runner cannot overwrite a canceled or terminated job with a later result. ### Array jobs Submitting with `arrayProperties.size` (2-10,000) fans out one child job per index, sharing the parent's job name and running through the same execution pipeline as a normal job (each child gets its own Docker container in `docker` mode). The parent's `status` and `arrayProperties.statusSummary` are computed live from its children on every `DescribeJobs`/`ListJobs` call rather than stored and updated incrementally, so there is nothing to race when many children finish concurrently. A queue-level `ListJobs` shows one entry per array job (the parent); pass `arrayJobId` to list its children. `CancelJob` and `TerminateJob` on the parent cascade to the children using the job-control rules above. ### Multi-node parallel (MNP) jobs A job definition registered with `"type": "multinode"` and `nodeProperties` (`numNodes`, `mainNode`, `nodeRangeProperties`) becomes an MNP job definition; `SubmitJob` against it (with optional `nodeOverrides`) runs one container per node concurrently in `docker` mode, each with `AWS_BATCH_JOB_NODE_INDEX`, `AWS_BATCH_JOB_MAIN_NODE_INDEX`, and `AWS_BATCH_JOB_NUM_NODES` set. The job's status, retry decision, and `startedAt`/`stoppedAt`/`statusReason` are all determined solely by the **main node** (matching AWS: a child node failing does not fail or retry the job). Every node normally runs to completion, while `TerminateJob` stops all running nodes. A natural main-node exit does not yet preempt the remaining nodes (see Limitations). `DescribeJobs`/queue-level `ListJobs` return one entry for the whole job (with `nodeProperties`, no per-node `container`); pass `multiNodeJobId` to `ListJobs` for a one-entry-per-node breakdown with each node's own `container` and `nodeProperties.nodeIndex`. `containerOverrides` and array jobs are not supported on MNP job definitions; use `nodeOverrides` instead. ## EventBridge EventBridge targets whose ARN points at a Batch job queue can include: ```json { "BatchParameters": { "JobDefinition": "my-job:1", "JobName": "nightly-job", "ArrayProperties": {"Size": 2}, "RetryStrategy": {"Attempts": 2} } } ``` When the rule fires, Floci submits an equivalent Batch job to the target queue. If the target payload contains a root `Parameters` object, those key/value pairs are stringified and passed as Batch submit parameters. Flat payload fields are not converted into Batch parameters. `ArrayProperties` is accepted and returned as target metadata for local deployment compatibility, but Batch still submits one local job and does not fan out array children. ## CloudFormation Floci provisions these resource types: - `AWS::Batch::ComputeEnvironment` - `AWS::Batch::JobQueue` - `AWS::Batch::JobDefinition` IAM roles, VPC fields, Fargate declarations, log configuration, storage, and resource requirements are accepted as metadata. Docker mode applies `MEMORY` requirements as container memory limits; local scheduling does not simulate AWS capacity, VCPU allocation, or VPC networking. ## Configuration | Variable | Default | Description | |---|---|---| | `FLOCI_SERVICES_BATCH_ENABLED` | `true` | Enable or disable Batch | | `FLOCI_SERVICES_BATCH_RUNNER_MODE` | `immediate` | `immediate` or `docker` | | `FLOCI_SERVICES_BATCH_DOCKER_NETWORK` | *(unset)* | Docker network for Batch containers | | `FLOCI_STORAGE_SERVICES_BATCH_MODE` | *(inherits global)* | Optional storage mode override | | `FLOCI_STORAGE_SERVICES_BATCH_FLUSH_INTERVAL_MS` | `5000` | Persistent storage flush interval | ## Limitations - No IAM enforcement. - No VPC/subnet/security-group simulation. - No AWS-faithful capacity scheduling. - No job dependencies (`dependsOn`). - EventBridge input transformers work through the existing EventBridge target input path; full Batch-specific input-transformer parity is not implemented. - An MNP job does not finish the instant its main node exits. AWS stops the job (and its remaining child nodes) as soon as the main node exits; Floci instead waits for every node's container to exit before scoring the attempt, so a child that outlives the main node keeps the job `RUNNING` longer than AWS would. `TerminateJob` can stop the whole job, but main-node completion does not yet trigger that same preemption path automatically. **Known follow-ups on the array/MNP surface** (not required for `SubmitJob`/`DescribeJobs`/`ListJobs` correctness, deliberately deferred): - `submitFromEventBridge` does not forward `arrayProperties`/`nodeOverrides` from a rule target's `BatchParameters`, even though `ArrayProperties` is accepted and echoed back as target metadata (see EventBridge section above). An EventBridge-triggered Batch job cannot fan out as an array or run as MNP today; only a direct `SubmitJob` call can. - CloudFormation's `AWS::Batch::JobDefinition` provisioner only registers `container`-type job definitions; there is no way to provision a `multinode` job definition via CloudFormation, only via a direct `RegisterJobDefinition` call. - `ListJobs` with `arrayJobId` ignores the `filters` parameter (only `jobStatus` is honored for children). This matches AWS's own note that filters don't apply to child jobs, but it means array children can't be filtered by `JOB_NAME`/`JOB_DEFINITION`/etc. - `ListJobs` with `multiNodeJobId` has no pagination (`maxResults`/`nextToken`); it always returns every node in one response.