Skip to content

Maintenance: Add Batch E2E tests for Lambda Managed Instances #5684

Description

@svozza

Summary

Add an end-to-end test validating Batch Processing's InvokeStore-backed state isolation on Lambda Managed Instances, where concurrent invocations are multiplexed into shared execution environments.

Part of #5092. This issue tracks the Batch portion; Logger is tracked in #5518 and Metrics in #5612.

Why is this needed?

BatchProcessingStore and SqsFifoProcessorStore scope records, the record handler, options, success and failure results, and FIFO failed-group tracking to the current invocation through InvokeStore. These code paths are currently exercised only by unit tests with mocked Lambda Managed Instances environments. Nothing proves that a BatchProcessor instance shared at module scope keeps its state isolated between concurrent invocations on the real platform.

Which area does this relate to?

  • Tests
  • Batch Processing

Solution

Add a Batch LMI end-to-end suite following the Logger and Metrics pattern from #5518 and #5612: a module-scoped promise barrier in the function code to guarantee an overlap, unique per-invocation identifiers, and many concurrent invocations held open so the scheduler multiplexes at least one pair into a shared execution environment. Reuse the shared capacity provider infrastructure and workflow support introduced by #5465.

Unlike Logger and Metrics there is no output stream to intercept: the observable state is the batchItemFailures response, so the handler simply returns it along with the message ids it processed.

Function code. Module-scoped BatchProcessor and SqsFifoPartialProcessor({ skipGroupOnError: true }) instances, as users write them. The record handler awaits the peer barrier on the first record of each batch only, so that overlapping invocations are both mid-process() with their own records registered in the store. That is the window in which a shared store would let one invocation's register() clobber the other's records and options, or mix failure messages.

const processor = new BatchProcessor(EventType.SQS);
const awaitPeer = createPeerBarrier();

export const handler = async (event: SQSEvent & { role: 'warmup' | 'test' }, context: Context) => {
  let first = true;
  let sawPeer = false;
  const recordHandler = async (record: SQSRecord) => {
    const { shouldFail } = JSON.parse(record.body);
    if (first && event.role === 'test') {
      first = false;
      sawPeer = await awaitPeer();
    }
    if (shouldFail) throw new Error(`Simulated failure for ${record.messageId}`);
  };
  const response = await processPartialResponse(event, recordHandler, processor, {
    context,
    throwOnFullBatchFailure: false,
  });
  return {
    invocationId: JSON.parse(event.Records[0].body).invocationId,
    executionEnvId,
    sawPeer,
    initializationType: process.env.AWS_LAMBDA_INITIALIZATION_TYPE ?? 'unset',
    maxConcurrency: process.env.AWS_LAMBDA_MAX_CONCURRENCY ?? 'unset',
    receivedMessageIds: event.Records.map((r) => r.messageId),
    failedMessageIds: response.batchItemFailures.map((f) => f.itemIdentifier),
  };
};

A second export does the same with the FIFO processor.

Test. Each invocation sends a synthetic SQS event whose message ids embed the invocation id (inv-3-msg-0) and whose bodies carry { invocationId, shouldFail }, with a failure pattern that differs between invocations. For the FIFO variant every invocation uses the same message group names (group-0, group-1), so a failed-group id leaked from a peer would make the processor skip this invocation's healthy records. Assertions per invocation, on the returned payload:

  • receivedMessageIds equals the invocation's own ids: catches records or handler overwritten by a peer's register().
  • failedMessageIds as a set equals the expected failures for that invocation's pattern (for FIFO, including the records short-circuited after a group failure): catches mixed failure messages, leaked failed-group ids, and failures lost to a peer's clear().
  • every failed id starts with the invocation's own prefix.
  • at least one result has sawPeer === true, and every result reports AWS_LAMBDA_INITIALIZATION_TYPE=lambda-managed-instances and AWS_LAMBDA_MAX_CONCURRENCY=10, as in the Metrics suite.

Run as describe.each over the standard and FIFO handlers, each attached to the capacity provider with perExecutionEnvironmentMaxConcurrency: 10.

Acknowledgment

Future readers

Please react with 👍 and your use case to help us understand customer demand.

Activity

added
batchThis item relates to the Batch Processing Utility
on Sep 9, 2026

karthiksenv commented on Oct 2, 2026

@karthiksenv
Contributor

Hi @svozza, I'd like to take this on. I've opened #5768 for the Batch LMI tests. Please assign this issue to me. Thanks!

added
pending-releaseThis item has been merged and will be released soon
and removed
pending-releaseThis item has been merged and will be released soon
on Oct 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

batchThis item relates to the Batch Processing Utility

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions