[MAR-3084] Add fetch-with-retries package#4
Open
leafrogers wants to merge 7 commits into
Open
Conversation
Add the first real shared package to this repo: @financial-times/martech-fetch-with-retries. This package is intentionally narrow. It is a wrapper around native Node fetch: not a general HTTP client and not a JSON parsing helper. It keeps fetch semantics by returning `Response`, retries thrown fetch errors and selected HTTP statuses, and leaves response parsing to the consumer. Key decisions in v1.0.0: - standardise fetch usage and retries across Martech repos - native fetch only; no custom fetch injection - requirement to pass in a logger, which warns on retry - only retries for idempotent methods by default - explicit opt-in booleans for POST and PATCH retries - explicit retry allowlist for 408, 429, 500, 502, 503 and 504 - no `Retry-After` support to keep the surface smaller, and none of our repos currently support it (https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Retry-After) - best-effort cancellation of discarded responses before retrying Includes unit, end-to-end and TypeScript smoke tests, plus package-local docs and changelog. Replaces the temporary workspace smoke-test package now that the real package provides the repo’s concrete example workspace.
Adds the release-only plumbing needed to publish the `fetch-with-retries` package from CircleCI to FT’s private Cloudsmith npm registry. I’ve already tested this with a pre-release (v0.1.0) and it worked fine, and have imported it successfully into a local clone of one of our other repos, for testing. The publishing workflow is tag-gated, package-scoped, and publishes via `npm publish --workspace packages/fetch-with-retries`. This repo uses Cloudsmith rather than public npm because the package is intended for internal use, and should not be published publicly.
saldixon
reviewed
Jun 9, 2026
saldixon
left a comment
Contributor
There was a problem hiding this comment.
review in progress, but thought I"d submit some questions so far.
saldixon
reviewed
Jun 10, 2026
saldixon
reviewed
Jun 10, 2026
saldixon
reviewed
Jun 11, 2026
leafrogers
commented
Jun 11, 2026
| const POST_METHOD = 'POST'; | ||
| const PATCH_METHOD = 'PATCH'; | ||
| const RETRYABLE_STATUS_CODES = new Set([ | ||
| HTTP_STATUS_CODES.REQUEST_TIMEOUT, |
Contributor
Author
There was a problem hiding this comment.
Can’t believe I left this unalphabetised
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Following on from the prep PR, this one adds the first real shared package using the new workflow. This package can then be imported into our projects as
@financial-times/martech-fetch-with-retries.Note
All thoughts and ideas are very welcome for this PR too!
Sum’ry
This PR is split out into two commits:
fetch-with-retriespackageThe package is intended to replace local fetch-retry helpers that we currently maintain in a few different repos, so we can stop solving the same problem slightly differently in several places.
Why this is happening
Across the Martech estate, we already have a few variants of “fetch, but retry when upstream is flaky”. They’re not all identical, but they’re close enough that it seems worth consolidating. This package caters to all of those variants.
What changed
Shared package
Added
@financial-times/martech-fetch-with-retries.Usage:
Default retry behaviour
By default, the package retries:
fetcherrors408,429,500,502,503,504And unless configured otherwise, only retries these idempotent methods:
GET,HEAD,OPTIONS,PUT,DELETERetries for
POSTandPATCHare explicit opt-ins via:retryPostRequestsretryPatchRequestsConfiguration
The wrapper supports:
maximumAttemptsbackoffStrategyretryPostRequestsretryPatchRequestsLogging
The package emits structured
debugandwarnretry events, and is intended to work with@dotcom-reliability-kit/logger.Tests/docs
Included:
Release/publish plumbing
This PR also adds the minimum publishing setup so the package is actually consumable:
🌸 🐄 🐖 🐓 🐈 🐑 🌸 🐄 🐖 🐓 🐈 🐑 🌸 🐄 🐖 🐓 🐈 🐑 🌸 🐄 🐖 🐓 🐈 🐑 🌸
A bit o’ context
Key decisions made
Native Node fetch only
This package assumes
globalThis.fetchand does not support custom fetch injection. That keeps the runtime and type surface smaller, and matches current usage in our repos.Transport-level only
This package retries requests and logs retry events, but it doesn’t parse JSON or normalize responses. That felt like the right split. Retry logic is the shared concern here; response/body handling can stay separate.
Sensible defaults
Retrying
POSTandPATCHby default felt too risky for a shared package, and looking around our repos, not all of them need it.No
Retry-Aftersupport in v1This was considered, and then removed as none of our existing repos use it.
It felt like edge-case handling that we don’t need at the moment. If we need more sophisticated delay behaviour later, we can revisit it or use
backoffStrategy.Publishing approach
This PR adds package publishing, but doesn’t introduce fully automated releasing, unlike
@dotcom-reliability-kit. Chat with me about why I decided against this, if you’re intrigued!So for now, the release model is intentionally simple:
fetch-with-retries-v1.0.1🌸 🐄 🐖 🐓 🐈 🐑 🌸 🐄 🐖 🐓 🐈 🐑 🌸 🐄 🐖 🐓 🐈 🐑 🌸 🐄 🐖 🐓 🐈 🐑 🌸
Next steps 🚀
When/if we’re happy with this package, we can start replacing retry helpers in a couple of repos. I’ve already tried it locally with ip-martech-scs-to-marketo and it seems good.
A moving depiction of this package