Sign in

    gaato/http/retry does not have a README file

    Backoff

    pub(all) struct Backoff {
    base_ms : Int
    max_ms : Int
    jitter : Jitter
    } derive(Eq,
    Debug
    )

    Exponential backoff: base_ms doubled per attempt up to max_ms, then jittered.

    Backoff::delay_ms

    fn Backoff::delay_ms(self : Backoff, attempt : Int, random : Double) -> Int

    The delay before retry number attempt + 1, in milliseconds.

    The exponential delay is base_ms * 2^attempt up to max_ms; a negative attempt counts as 0, and a nonpositive base_ms or max_ms gives 0. random is clamped into [0, 1), NaN to 0. The jitter then applies: NoJitter keeps the delay, Full takes trunc(delay * random), and Proportional(lo~, hi~) multiplies by lo + trunc(random * (hi - lo)) per mille, in integers. The jittered delay is capped at max_ms again, so a hi above 1000 spreads delays below the cap but never past it.

    test {
    let backoff : @retry.Backoff = {
    base_ms: 500,
    max_ms: 30000,
    jitter: Proportional(lo=800, hi=1200),
    }
    assert_eq(backoff.delay_ms(2, 0.5), 2000)
    assert_eq(backoff.delay_ms(0, 0.0), 400)
    }

    Backoff::equal

    fn Backoff::equal(Backoff, Backoff) -> Bool

    Equality for backoff settings.

    Backoff::not_equal

    fn Backoff::not_equal(x : Backoff, y : Backoff) -> Bool

    Equality for backoff settings.

    Backoff::to_repr

    Debug representation of backoff settings.

    Decision

    pub(all) enum Decision {
    Wait(Int)
    Stop(StopReason)
    } derive(Eq,
    Debug
    )

    What to do after a failed attempt.

    Decision::equal

    fn Decision::equal(Decision, Decision) -> Bool

    Equality for decisions.

    Decision::not_equal

    fn Decision::not_equal(x : Decision, y : Decision) -> Bool

    Equality for decisions.

    Decision::to_repr

    Debug representation of a decision.

    Jitter

    pub(all) enum Jitter {
    NoJitter
    Full
    Proportional(lo~ : Int, hi~ : Int)
    } derive(Eq,
    Debug
    )

    How the exponential delay is spread, so that clients do not retry in lockstep. Multipliers are per mille.

    Jitter::equal

    fn Jitter::equal(Jitter, Jitter) -> Bool

    Equality for jitter settings.

    Jitter::not_equal

    fn Jitter::not_equal(x : Jitter, y : Jitter) -> Bool

    Equality for jitter settings.

    Jitter::to_repr

    Debug representation of a jitter setting.

    Methods

    pub(all) enum Methods {
    Never
    Idempotent
    Listed(Array[String])
    Any
    } derive(Eq,
    Debug
    )

    Which request methods a retry is allowed for.

    Methods::equal

    fn Methods::equal(Methods, Methods) -> Bool

    Equality for method sets.

    Methods::not_equal

    fn Methods::not_equal(x : Methods, y : Methods) -> Bool

    Equality for method sets.

    Methods::to_repr

    Debug representation of a method set.

    Outcome

    pub(all) enum Outcome {
    Response(status~ : Int, headers~ :
    Headers
    )
    Failure(
    HttpError
    )
    } derive(
    Debug
    )

    The result of an attempt that did not succeed.

    Outcome::to_repr

    Debug representation of an outcome.

    RetryAfter

    pub(all) struct RetryAfter {
    source : RetryAfterSource
    cap : RetryAfterCap
    zero_means_backoff : Bool
    } derive(Eq,
    Debug
    )

    How a server-requested delay is read and bounded.

    RetryAfter::equal

    fn RetryAfter::equal(RetryAfter, RetryAfter) -> Bool

    Equality for delay settings.

    RetryAfter::not_equal

    fn RetryAfter::not_equal(x : RetryAfter, y : RetryAfter) -> Bool

    Equality for delay settings.

    RetryAfter::to_repr

    Debug representation of delay settings.

    RetryAfterCap

    pub(all) enum RetryAfterCap {
    StopAbove(Int)
    BackoffAbove(Int)
    NoCap
    } derive(Eq,
    Debug
    )

    What to do with a server-requested delay longer than a limit, in milliseconds.

    RetryAfterCap::equal

    Equality for delay caps.

    RetryAfterCap::not_equal

    fn RetryAfterCap::not_equal(x : RetryAfterCap, y : RetryAfterCap) -> Bool

    Equality for delay caps.

    RetryAfterCap::to_repr

    Debug representation of a delay cap.

    RetryAfterSource

    pub(all) enum RetryAfterSource {
    Ignore
    Header
    MsThenHeader
    } derive(Eq,
    Debug
    )

    Where a server-requested delay is read from.

    RetryAfterSource::equal

    Equality for delay sources.

    RetryAfterSource::not_equal

    fn RetryAfterSource::not_equal(x : RetryAfterSource, y : RetryAfterSource) -> Bool

    Equality for delay sources.

    RetryAfterSource::to_repr

    Debug representation of a delay source.

    RetryRule

    pub(all) struct RetryRule {
    max_retries : Int
    statuses : Array[StatusRule]
    sent_failures : Methods
    unsent_failures : Bool
    override_header : String?
    retry_after : RetryAfter
    backoff : Backoff
    } derive(Eq,
    Debug
    )

    A retry policy as data: what may be retried, how long to wait, and when to stop. decide applies it to one failed attempt.

    test {
    let rule : @retry.RetryRule = {
    ..@retry.RetryRule::never(),
    max_retries: 2,
    statuses: [{ statuses: [Code(429), Range(500, 599)], methods: Idempotent, }],
    backoff: { base_ms: 500, max_ms: 8000, jitter: NoJitter, },
    }
    let get = @http.Request::get("/items")
    let busy = @retry.Response(status=503, headers=@http.Headers::new())
    assert_eq(rule.decide(busy, get, attempt=1, random=0.0), Wait(1000))
    assert_eq(rule.decide(busy, get, attempt=2, random=0.0), Stop(Exhausted))
    }

    RetryRule::decide

    fn RetryRule::decide(self : RetryRule, outcome : Outcome, request :
    Request
    , attempt~ : Int, random~ : Double, now_unix_ms? : Int64, remaining_ms? : Int64, server_delay_ms? : Int, idempotent? : Bool, replayable? : Bool) -> Decision

    Decides whether to retry after a failed attempt, and how long to wait.

    attempt counts the retries already made: 0 after the first attempt fails. The checks run in order, and the first that applies wins:

    1. attempt >= max_retries stops with Exhausted.
    2. A body that cannot be sent again stops with NotReplayable; replayable overrides request.body.is_replayable().
    3. A response carrying override_header with the value true (ignoring case and surrounding whitespace) skips step 4; false stops with ServerSaidNo; any other value is ignored.
    4. The outcome must be retryable for the request's method: a response through the first StatusRule containing its status; Protocol never; Proxy when unsent_failures is set and its status matches a StatusRule; another unsent failure when unsent_failures is set; any other failure through sent_failures. Idempotent asks @http.is_idempotent unless idempotent is given.
    5. The wait is server_delay_ms when given, otherwise the response's header per retry_after.source (an HTTP date needs now_unix_ms), bounded by retry_after.cap; without one it is backoff.delay_ms(attempt, random).
    6. With remaining_ms, a wait that is not shorter than it stops with Budget(wait).

    test {
    let rule : @retry.RetryRule = {
    ..@retry.RetryRule::never(),
    max_retries: 2,
    statuses: [{ statuses: [Code(429)], methods: Any, }],
    retry_after: {
    source: Header,
    cap: StopAbove(60000),
    zero_means_backoff: false,
    },
    }
    let post = @http.Request::post("/messages")
    let headers = @http.Headers::from_array([("Retry-After", "3")])
    let limited = @retry.Response(status=429, headers~)
    assert_eq(rule.decide(limited, post, attempt=0, random=0.5), Wait(3000))
    assert_eq(
    rule.decide(limited, post, attempt=0, random=0.5, remaining_ms=2000),
    Stop(Budget(3000)),
    )
    }

    RetryRule::equal

    fn RetryRule::equal(RetryRule, RetryRule) -> Bool

    Equality for retry rules.

    RetryRule::never

    fn RetryRule::never() -> RetryRule

    A rule that never retries, and a base to build others on with { ..never(), ... }.

    RetryRule::not_equal

    fn RetryRule::not_equal(x : RetryRule, y : RetryRule) -> Bool

    Equality for retry rules.

    RetryRule::to_repr

    Debug representation of a retry rule.

    StatusMatch

    pub(all) enum StatusMatch {
    Code(Int)
    Range(Int, Int)
    } derive(Eq,
    Debug
    )

    A status code, or an inclusive range of status codes.

    test {
    let rule : @retry.StatusRule = {
    statuses: [Code(429), Range(500, 599)],
    methods: Any,
    }
    assert_eq(rule.statuses.length(), 2)
    }

    StatusMatch::equal

    fn StatusMatch::equal(StatusMatch, StatusMatch) -> Bool

    Equality for status matches.

    StatusMatch::not_equal

    fn StatusMatch::not_equal(x : StatusMatch, y : StatusMatch) -> Bool

    Equality for status matches.

    StatusMatch::to_repr

    Debug representation of a status match.

    StatusRule

    pub(all) struct StatusRule {
    statuses : Array[StatusMatch]
    methods : Methods
    } derive(Eq,
    Debug
    )

    Response statuses that may be retried, and for which methods.

    StatusRule::equal

    fn StatusRule::equal(StatusRule, StatusRule) -> Bool

    Equality for status rules.

    StatusRule::not_equal

    fn StatusRule::not_equal(x : StatusRule, y : StatusRule) -> Bool

    Equality for status rules.

    StatusRule::to_repr

    Debug representation of a status rule.

    StopReason

    pub(all) enum StopReason {
    Exhausted
    NotRetryable
    MethodNotAllowed
    NotReplayable
    ServerSaidNo
    RetryAfterTooLong(Int)
    Budget(Int)
    } derive(Eq,
    Debug
    )

    Why decide stopped.

    StopReason::equal

    fn StopReason::equal(StopReason, StopReason) -> Bool

    Equality for stop reasons.

    StopReason::not_equal

    fn StopReason::not_equal(x : StopReason, y : StopReason) -> Bool

    Equality for stop reasons.

    StopReason::to_repr

    Debug representation of a stop reason.

    Powered by MoonBit

    Site sourceReport issuePackagesBuild queueSkillsStatistics

    © 2026 mooncakes.io