-module(aws@waiter). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/aws/waiter.gleam"). -export([wait/4]). -export_type([step/1, waiter_error/1]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC( " Polling helper for Smithy `@waitable` operations.\n" "\n" " The codegen-emitted `wait_until_` functions are thin\n" " wrappers over `wait`. Each wrapper:\n" "\n" " 1. Invokes the underlying typed operation in a `step` closure.\n" " 2. Matches the result against the waiter's acceptors (a list\n" " of `state` + `matcher` rules lifted from the Smithy trait).\n" " Returns `Settled` when an acceptor with `state: success`\n" " matches, `FailedNow(err)` when `state: failure` matches,\n" " `Continue` otherwise.\n" " 3. Calls `wait(step, max_attempts, min_delay, max_delay)` to\n" " drive the loop with exponential backoff between attempts.\n" "\n" " Backoff doubles the previous delay (starting at `min_delay_ms`)\n" " up to `max_delay_ms` — Smithy's standard waiter cadence. The\n" " helper sleeps between attempts via `process.sleep`; tests pass\n" " zero delays so they don't block.\n" "\n" " `step` carries the 1-indexed attempt number. The codegen\n" " generally ignores it but specialised callers can use it for\n" " dynamic adjustments (e.g. emit a log line per attempt).\n" ). -type step(OLU) :: settled | continue | {failed_now, OLU}. -type waiter_error(OLV) :: {failed, OLV} | {max_attempts_exceeded, integer()}. -file("src/aws/waiter.gleam", 103). ?DOC( " Smithy's waiter backoff: double the previous delay, capped at\n" " `max_delay_ms`. Starts at `min_delay_ms` (the first sleep) and\n" " climbs from there.\n" ). -spec next_delay(integer(), integer()) -> integer(). next_delay(Current_ms, Max_delay_ms) -> Doubled = Current_ms * 2, case Doubled > Max_delay_ms of true -> Max_delay_ms; false -> Doubled end. -file("src/aws/waiter.gleam", 111). -spec sleep(integer()) -> nil. sleep(Ms) -> case Ms =< 0 of true -> nil; false -> gleam_erlang_ffi:sleep(Ms) end. -file("src/aws/waiter.gleam", 70). -spec loop( fun((integer()) -> step(OMB)), integer(), integer(), integer(), integer() ) -> {ok, nil} | {error, waiter_error(OMB)}. loop(Step, Attempt, Max_attempts, Current_delay_ms, Max_delay_ms) -> case Step(Attempt) of settled -> {ok, nil}; {failed_now, E} -> {error, {failed, E}}; continue -> case Attempt >= Max_attempts of true -> {error, {max_attempts_exceeded, Max_attempts}}; false -> sleep(Current_delay_ms), loop( Step, Attempt + 1, Max_attempts, next_delay(Current_delay_ms, Max_delay_ms), Max_delay_ms ) end end. -file("src/aws/waiter.gleam", 58). ?DOC( " Drive a waiter step closure to completion, sleeping between\n" " attempts with exponential backoff capped at `max_delay_ms`.\n" " Returns `Ok(Nil)` on settle, `Error(Failed(_))` on a\n" " `state: failure` acceptor match, `Error(MaxAttemptsExceeded(_))`\n" " when the attempt budget is exhausted. `max_attempts == 0` is a\n" " defensive guard that returns immediately without invoking\n" " `step`.\n" ). -spec wait(fun((integer()) -> step(OLW)), integer(), integer(), integer()) -> {ok, nil} | {error, waiter_error(OLW)}. wait(Step, Max_attempts, Min_delay_ms, Max_delay_ms) -> case Max_attempts > 0 of false -> {error, {max_attempts_exceeded, 0}}; true -> loop(Step, 1, Max_attempts, Min_delay_ms, Max_delay_ms) end.