Skip to content

Maintenance: document how to test invocation-scoped state with the InvokeStore #5619

Description

@svozza

Summary

Logger, Metrics and Batch keep per-invocation state in the Lambda InvokeStore when AWS_LAMBDA_MAX_CONCURRENCY is set. The unit tests for that behaviour, in each package's tests/unit/concurrency/ folder, depend on two properties of @aws/lambda-invoke-store that are not written down anywhere in the repo:

  1. The global is published lazily. globalThis.awslambda.InvokeStore, which our stores read, only exists after something has called InvokeStore.getInstanceAsync(). In a real function the runtime does this at startup; in tests nothing does it for you.
  2. The instance is cached at module level and its type is fixed on first creation. If AWS_LAMBDA_MAX_CONCURRENCY is in process.env at the time of the first getInstanceAsync() call you get the AsyncLocalStorage-backed store that isolates invocations. Otherwise you get a single-context store whose run() overwrites one field and provides no isolation. Later calls return the cached instance regardless of the environment.

This is why packages/testing/src/setupEnv.ts sets AWS_LAMBDA_BENCHMARK_MODE=1 (it makes the package expose InvokeStore._testing.reset()), why every concurrency test calls reset() in beforeEach, and why sequence() in testing-utils calls getInstanceAsync() before running the invocations. It is also why tests that touch invocation-scoped state before sequence() runs (a constructor writing a default, or a test of the fallback to shared state outside any invocation) need an explicit await InvokeStore.getInstanceAsync() placed after the env stub. #5615 adds several of these and the reason is not obvious from the diff.

The trap is that getting the order wrong does not error. Calling getInstanceAsync() before the env stub, e.g. by hoisting it into a beforeEach that runs ahead of a per-test vi.stubEnv, caches the non-isolating store and the tests fail on assertions because one invocation reads the other's state. getInstanceAsync(true) forces the isolating store if a single hoisted call is wanted.

Why is this needed?

None of this is discoverable from our code; it has to be re-derived from the @aws/lambda-invoke-store source each time, which came up again while reviewing #5615. Anyone adding a store, writing a new concurrency test, or adapting to a change in how the RIC exposes the InvokeStore needs to know it, and so does any LLM-based tooling working in the repo.

We should document this where both contributors and coding agents will find it. Since #5618 retired the docs/contributing/ pages, unit test conventions live in the "Unit tests" section of CODING_STANDARDS.md, which CONTRIBUTING.md names as the source of truth and AGENTS.md instructs agents to read before touching tests. That makes it the natural home, and its "Environment" list already covers the related vi.stubEnv() / vi.unstubAllEnvs() rule.

Which area does this relate to?

Tests, Commons, Logger, Metrics, Batch Processing

Solution

Add a short subsection or bullet group to the "Unit tests" section of CODING_STANDARDS.md covering the mechanism above, the reset() / getInstanceAsync() ordering rule with a minimal example, and the vi.stubGlobal('awslambda', undefined) / vi.unstubAllGlobals() pairing used by the "InvokeStore is not available" tests. Keep it in the same terse, rule-per-bullet style as the rest of that file, and consider a one-line pointer to it from the sequence() JSDoc in packages/testing/src/helpers.ts and a comment on the AWS_LAMBDA_BENCHMARK_MODE line in setupEnv.ts, since those are where someone hits the problem.

Acknowledgment

Future readers

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

Activity

  1. added
    internalPRs that introduce changes in governance, tech debt and chores (linting setup, baseline, etc.)
    on Sep 3, 2026
  2. removed
    internalPRs that introduce changes in governance, tech debt and chores (linting setup, baseline, etc.)
    on Sep 7, 2026
  3. self-assigned this
    on Sep 7, 2026
  4. powertools-for-aws-oss-automation commented on Sep 7, 2026

    @powertools-for-aws-oss-automation

    Warning

    This issue is now closed. Please be mindful that future comments are hard for our team to see.
    If you need more assistance, please either reopen the issue, or open a new issue referencing this one.
    If you wish to keep having a conversation with other community members under this issue feel free to do so.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions