Skip to content

Deduplicate concurrent credential refreshes in Signer #837

Description

@Xuanwo

Context

Signer::sign currently clones the cached credential under a synchronous mutex, releases the mutex, and then awaits ProvideCredential when the cache is empty or stale. Concurrent requests that observe the same empty or stale cache can therefore invoke the provider at the same time.

This becomes visible with short-lived or remote-issued credentials such as S3 Express CreateSession credentials: a cold start or five-minute refresh boundary can produce a burst of equivalent issuance requests. The same behavior can affect metadata, STS, and other network-backed providers.

This issue is specific to the credential cache owned by Signer. It does not change the #801 contract that Granter does not cache granted output or promise generic singleflight.

Proposed behavior

Make credential loading and refresh singleflight per shared Signer cache generation:

  • one caller performs ProvideCredential I/O for an empty or stale generation;
  • concurrent callers wait for that result and reuse the same valid credential;
  • a failed refresh is returned to current waiters but is not cached permanently;
  • a later call can attempt refresh again;
  • request signing itself remains concurrent and does not run under the refresh lock.

The implementation must preserve clone cache sharing, with_context and with_credential_provider cache reset behavior, and the native/WASM MaybeSend contract.

Acceptance criteria

  • A concurrent cold-start test proves exactly one provider invocation.
  • A concurrent stale-credential test proves exactly one refresh invocation.
  • A failed refresh does not poison the cache and a later call can recover.
  • Different signer caches do not block each other.
  • Credential values remain absent from Debug and errors.
  • Existing exact required_valid_until checks continue to run against the refreshed credential.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestrustPull requests that update Rust code

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions