Overcast is alpha — behaviour and APIs may change between releases. Pin your version and read the changelog before upgrading.

overcast

Lambda concurrency

How many containers Overcast will run for a function, what happens to an invocation that cannot get one, and how reserved and provisioned concurrency behave.

How many containers Lambda will run at once, and what happens to an invocation that cannot get one.

The limits

These size the pool to your Docker host. They are not AWS’s account quota, which Overcast does not emulate.

LimitEnvironment variableDefaultWhen reached
Containers across all functionsLAMBDA_MAX_INSTANCESauto (25 fallback)Reclaim an idle container → queue → throttle
Containers for one functionLAMBDA_MAX_INSTANCES_PER_FUNCTIONauto (10 fallback)Queue → throttle
Aggregate container memory (Σ MemorySize)LAMBDA_MAX_MEMORY_MBauto (unlimited fallback)Reclaim an idle container → queue → throttle
Idle containers kept per functionLAMBDA_MAX_WARM_INSTANCES10Surplus destroyed on release
Concurrent container startsLAMBDA_DOCKER_MAX_CONCURRENT_STARTSauto (4 fallback)Starts queue behind a semaphore
ReservedConcurrentExecutionsper function, AWS APIunsetThrottle immediately

Derivations and every other LAMBDA_* variable are in the environment variable reference.

An invocation that cannot get a container first reclaims the least-recently-used idle one — never a provisioned one — and then waits. If it is still waiting when the function’s timeout expires it is throttled, with a 429 TooManyRequestsException and Reason: ConcurrentInvocationLimitExceeded.

The memory budget

LAMBDA_MAX_MEMORY_MB counts bytes, not containers: a new container is admitted only while Σ MemorySize of live containers plus its own stays inside the budget. Each container is hard-capped at its function’s MemorySize with swap disabled, so the sum is a real bound.

Above ~90% of the budget the pool changes behaviour: a container whose invocation has just finished is destroyed rather than kept warm, so queued work regains budget without waiting for the 15-minute idle sweep. Provisioned environments are always kept and a running invocation is never interrupted. Entering and leaving that regime is logged once each — expect cold starts while it lasts.

Reserved concurrency

ReservedConcurrentExecutions is enforced with AWS’s semantics rather than the pool’s: no queueing, an immediate 429 with Reason: ReservedFunctionConcurrentInvocationLimitExceeded. Setting it to 0 disables the function, the same idiom that works on AWS.

Asynchronous invocations are never throttled back to the caller — they were already answered 202 — and are retried internally. Event source mappings behave the same way: a throttled batch is left in flight, so the messages return on the visibility timeout. Event delivery and retries covers the retry budget and where an exhausted event ends up.

Provisioned concurrency

Environments are created in the background (Status: IN_PROGRESS, then READY), held open regardless of the idle sweep, replenished when one is lost, and rebuilt against the new configuration after a code or config update. Containers report AWS_LAMBDA_INITIALIZATION_TYPE=provisioned-concurrency, the variable Powertools and similar libraries read to classify a cold start.

Provisioned concurrency is a floor, not a ceiling: when all reserved environments are busy, further invocations spill over into on-demand capacity with a cold start rather than being throttled, matching AWS, where only reserved concurrency caps a function. A reservation is never reclaimed for another function. Without Docker nothing can be allocated, so the configuration is stored and reported Status: FAILED with a StatusReason rather than claiming READY.