aws/internal/credentials_cache

Credentials cache: a gleam_otp actor that owns a Provider and caches the last successful Credentials. Re-fetches when the cached value is within buffer_seconds of its expires_at, or when the cache is empty (first call) or the previous fetch failed.

Non-expiring credentials (expires_at = None) are cached forever — env vars don’t rotate without a process restart, so re-reading them on every signed request would be wasteful.

Concurrency: actor messages are handled sequentially, so two parallel get calls during the first fetch coalesce into a single provider invocation. No thundering-herd shielding beyond that — adequate for the rates AWS SDKs see in practice.

Types

Opaque handle for the cache. Hold one per Client you build.

pub opaque type Cache
pub type StartError {
  StartFailed(actor.StartError)
}

Constructors

Values

pub fn as_provider(cache: Cache) -> credentials.Provider

Re-expose the cache as a regular Provider. The returned provider’s fetch closure proxies to get(cache) — so the rest of the SDK can thread Provider values around as before, but now hot-path reads debounce into the actor and avoid re-running the seven-stage chain on every signed request.

pub const default_buffer_seconds: Int

Default refresh buffer: trigger a refresh five minutes before expiry. Tracks the conservative value most AWS SDKs use.

pub fn get(
  cache: Cache,
) -> Result(credentials.Credentials, credentials.ProviderError)

Fetch the current credentials, refreshing from the wrapped provider if the cache is empty or the credentials are within the refresh buffer of expiry. Returns whatever the provider produced — the cache itself never fabricates errors.

pub fn shutdown(cache: Cache) -> Nil

Tell the cache actor to exit. Fire-and-forget. See aws/internal/actor_lifecycle.shutdown_via_stop for the contract; idempotent because Erlang silently drops sends to a dead Pid.

pub fn shutdown_sync(
  cache: Cache,
  timeout_ms: Int,
) -> Result(Nil, Nil)

Synchronous teardown — monitors the actor, sends Stop, waits for DOWN. Ok(Nil) on clean exit, Error(Nil) only on real timeout. Already-dead actors short-circuit to Ok(Nil) via subject_owner returning Error.

pub fn start(
  provider provider: credentials.Provider,
  clock clock: fn() -> Int,
  buffer_seconds buffer_seconds: Int,
) -> Result(Cache, StartError)

Start the cache actor.

  • provider: the upstream provider this cache wraps. Can itself be a credentials.chain([...]) — the cache doesn’t care.
  • clock: returns unix seconds. The default production wiring uses erlang:system_time(second); tests pass a closure over a controlled counter so they can fast-forward across expiries.
  • buffer_seconds: trigger a refresh this many seconds before expires_at. See default_buffer_seconds.
pub fn start_default(
  provider provider: credentials.Provider,
) -> Result(Cache, StartError)

Start a cache using the OS clock and default_buffer_seconds. For production wiring this is almost always what you want.

Search Document