GhEx.RateLimit (gh_ex v0.1.0)

Copy Markdown View Source

Rate-limit headers and an opt-in retry for GitHub's rate limits.

from_response/1 parses the x-ratelimit-* headers into a snapshot.

retry/2 is a Req-compatible retry policy. Req already retries ordinary transient errors (5xx, network errors) on its own; this adds awareness of GitHub's secondary rate limits, which arrive as a 403 (not retried by default) carrying a retry-after header or x-ratelimit-remaining: 0. Enable it through :req_options:

GhEx.new(
  auth: {:token, token},
  req_options: [retry: &GhEx.RateLimit.retry/2]
)

Req bounds the attempts with :max_retries (default 3).

Summary

Functions

Builds a snapshot from a response, or nil when no rate-limit headers exist.

A Req-compatible retry policy that understands GitHub's rate limits.

Types

t()

@type t() :: %GhEx.RateLimit{
  limit: non_neg_integer() | nil,
  remaining: non_neg_integer() | nil,
  reset: DateTime.t() | nil,
  resource: String.t() | nil,
  used: non_neg_integer() | nil
}

Functions

from_response(resp)

@spec from_response(Req.Response.t()) :: t() | nil

Builds a snapshot from a response, or nil when no rate-limit headers exist.

retry(request, resp)

@spec retry(Req.Request.t(), Req.Response.t() | Exception.t()) ::
  {:delay, non_neg_integer()} | boolean()

A Req-compatible retry policy that understands GitHub's rate limits.

Returns {:delay, ms} for a 403 or 429 that signals a rate limit, waiting the retry-after header or, when x-ratelimit-remaining is 0, until x-ratelimit-reset. Other 429s and the usual transient statuses (408, 500, 502, 503, 504) return true so Req applies its own backoff. A plain 403 (an authorization failure, not a rate limit) is not retried. Wire it in through :req_options; Req applies :max_retries.