Skip to content

fix: retry transient GitHub API errors without duplicating dispatches - #115

Open
eeree wants to merge 1 commit into
benc-uk:mainfrom
eeree:feat/octokit-retry-throttling
Open

eeree wants to merge 1 commit into
benc-uk:mainfrom
eeree:feat/octokit-retry-throttling

Conversation

@eeree

@eeree eeree commented Oct 14, 2026

Copy link
Copy Markdown

Fixes #114

Summary

Adds @octokit/plugin-retry and @octokit/plugin-throttling to the Octokit client, so transient errors and rate limits no longer fail the action. Dispatch is not retried after server or network errors, which avoids duplicate runs. Status polling keeps going through transient errors until wait-timeout-seconds.

Changes

  • src/octokit-client.ts (new)
    • createOctokit() adds both official plugins to github.getOctokit:
      • retry: 3 attempts with 1s/4s/9s backoff; client errors are never retried
      • throttling: up to 3 retries on primary and secondary rate limits, each logged as a warning annotation
    • NO_RETRY_REQUEST_OPTIONS turns off plugin-retry for one request. Rate limits on that request are still retried by the throttling plugin.
    • isTransientError() uses the same rule as plugin-retry to decide whether an error is transient.
  • src/wait-for-run.ts (new)
    • The polling loop moved here from run(). The clock, sleep and logger can be injected, so the loop can be tested.
    • After a transient error it logs a warning and keeps polling, up to the existing timeout.
    • Any other error fails immediately.
  • src/main.ts
    • Dispatch uses NO_RETRY_REQUEST_OPTIONS.
    • Polling goes through waitForRunCompletion().
    • Log output is unchanged.
  • Tests:
    • The real client config and plugins run against a scripted fetch. Covered:
      • 5xx and network errors are retried
      • the client gives up after 3 retries
      • 404 is not retried
      • a secondary rate limit is retried
      • dispatch is not retried after 500 or a network error, but is retried after a secondary rate limit
    • The polling loop runs on a fake clock. Covered: success, transient errors, non-transient errors, and timeout (both while the run stays active and when errors never stop).
    • In tests, the throttling plugin's shared 1s spacing between write requests is replaced with a pass-through. Retry and rate limit handling still use the real plugin code.
  • Tooling
    • New typecheck and test scripts, and @types/node.
    • Runtime packages moved to dependencies.
    • tsconfig: noEmit and allowImportingTsExtensions; test files are now typechecked.
  • dist/index.js rebuilt.

Behaviour changes

Situation Before After
5xx or network error when listing workflows, polling, or fetching the final status Step fails Retried up to 3× with backoff
Rate limit (primary or secondary) Step fails Waits for retry-after or the reset time, up to 3×, with a warning
5xx or network error on dispatch Step fails Step fails (unchanged, on purpose: avoids duplicate runs)
Transient error still failing after retries, while polling Step fails Warning, polling continues until wait-timeout-seconds
Client errors (401, 404, 422, …) Step fails Step fails (unchanged)

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Transient GitHub API errors fail the action; naive retries could duplicate dispatched runs

1 participant