Skip to content

feat(client): add request timeout and retry with backoff#36

Merged
pchuri merged 1 commit into
mainfrom
feat/client-resilience
May 10, 2026
Merged

feat(client): add request timeout and retry with backoff#36
pchuri merged 1 commit into
mainfrom
feat/client-resilience

Conversation

@pchuri
Copy link
Copy Markdown
Owner

@pchuri pchuri commented May 10, 2026

Summary

Add a 30s default request timeout and a retry interceptor in lib/jira-client.js so the CLI:

  • no longer hangs forever on network drops, and
  • no longer fails immediately on 429/5xx blips.

Retry policy

Condition Behavior
429 Retry, honor Retry-After header if present, otherwise exponential backoff
5xx Retry with exponential backoff
Network: ECONNRESET, ECONNABORTED, ETIMEDOUT, ENOTFOUND, EAI_AGAIN Retry with exponential backoff
4xx other than 429 Reject immediately (no retry)
Up to 3 attempts after initial request Backoff: 1s → 2s → 4s

The interceptor is applied to all three axios clients (clientV2, clientV3, agileClient) via a shared createAxiosClient helper, removing duplication from the previous per-client interceptor setup.

Configuration (env-only, no config schema changes)

Var Default Notes
JIRA_CLI_TIMEOUT_MS 30000 Request timeout in ms
JIRA_CLI_MAX_RETRIES 3 Set to 0 to disable retries entirely

Invalid or non-positive values fall back to defaults.

Why

The previous client had no timeout and no retry logic — a transient 503 or rate-limit response was a hard failure, and a stalled connection would hang the CLI indefinitely. Long-running scripts (e.g. CI bulk operations) and users on flaky networks were the most affected.

Test plan

  • npm test — 273 tests pass (+22 new)
  • npm run lint — clean
  • Unit coverage for shouldRetry (429, 5xx, network codes, 4xx skip)
  • Unit coverage for computeRetryDelay (exponential backoff, Retry-After lowercase + capitalized, fallback)
  • End-to-end retry coverage via mocked axios adapter (eventual success, max-retries exhaustion, 404 no-retry, MAX_RETRIES=0 disables retries, exponential backoff sequence verified)
  • Timeout default + env override + invalid-value fallback verified on all three clients (V2, V3, agile)

Adds a 30s default request timeout and a retry interceptor that handles
transient failures so the CLI no longer hangs forever on network drops
or fails immediately on 429/5xx blips.

Retry policy:
  - retryable: 429, 5xx, and ECONNRESET/ECONNABORTED/ETIMEDOUT/
    ENOTFOUND/EAI_AGAIN network errors
  - non-retryable: 4xx other than 429
  - up to 3 attempts after the initial request
  - exponential backoff: 1s, 2s, 4s
  - 429 responses honor the Retry-After header when present

Configurable via env (no config schema changes):
  - JIRA_CLI_TIMEOUT_MS (default: 30000)
  - JIRA_CLI_MAX_RETRIES (default: 3, set to 0 to disable retries)
@pchuri pchuri self-assigned this May 10, 2026
@pchuri pchuri merged commit 8a99787 into main May 10, 2026
5 checks passed
@pchuri pchuri deleted the feat/client-resilience branch May 10, 2026 07:32
github-actions Bot pushed a commit that referenced this pull request May 10, 2026
# [2.8.0](v2.7.0...v2.8.0) (2026-05-10)

### Features

* **client:** add request timeout and retry with backoff ([#36](#36)) ([8a99787](8a99787))
@github-actions
Copy link
Copy Markdown

🎉 This PR is included in version 2.8.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant