5.7 KiB
5.7 KiB
Archived 2026-04-19: all tasks retroactively ticked; package shipped under universal/control-flow/retry.
Tasks: enterprise-retry
1. Scaffold
- 1.1 Create
packages/universal/retry/withpackage.json,tsconfig.json,tsconfig.lib.json,vite.config.ts,vitest.config.ts,README.mdskeleton - 1.2 Register coverage thresholds at 100/100/100/100 in
vitest.config.ts; provider = istanbul - 1.3 Add cross-cutting guard tests in
tests/: dep-graph, no-disallowed, tree-shake - 1.4 Add package to root
CLAUDE.md,README.md, andSTRUCTURE.yml
2. Types + errors
- 2.1 Implement
src/types/retry.types.ts—RetryConfig,RetryResult,RetryStrategy,DelayFunction,JitterMode,ConstantBackoffOptions,LinearBackoffOptions,ExponentialBackoffOptions - 2.2 Implement
src/errors/retry-error.ts—RetryErrorbase extendsSuaveplanError;RetryExhaustedError,AttemptTimeoutErrorextendRetryError;defineCodesforRETRY.EXHAUSTED,RETRY.ABORTED,RETRY.TIMEOUT - 2.3 Implement
src/circuit-breaker/circuit-breaker.types.ts—CircuitBreakerConfig,CircuitBreakerEventMap,CircuitState;CircuitOpenErrorextendsRetryErrorwithRETRY.CIRCUIT_OPENcode - 2.4 Zod schemas:
RetryConfigSchema,ConstantBackoffOptionsSchema,LinearBackoffOptionsSchema,ExponentialBackoffOptionsSchema,CircuitBreakerConfigSchema - 2.5 Tests: error construction, code narrowing,
.attempts/.lastError/.attemptNumber/.timeoutMsfields - 2.6 Implement
src/error-codes.tsand auto-register via side-effect import insrc/index.ts
3. Backoff strategies
- 3.1
src/strategies/constant/constant.ts—createConstantBackoff(opts)→RetryStrategy;ConstantBackoffOptions - 3.2
src/strategies/linear/linear.ts—createLinearBackoff(opts)→RetryStrategy;LinearBackoffOptions - 3.3
src/strategies/exponential/exponential.ts—createExponentialBackoff(opts)→RetryStrategy;applyJitter(delay, mode, rng?),clampDelay(delay, min, max);ExponentialBackoffOptions - 3.4 All strategies accept injectable
rng?: Rngfor deterministic jitter - 3.5 Unit tests: delay values at each attempt, clamping, jitter modes (full/equal/decorrelated/none)
- 3.6 Property-based tests: exponential
delay(n+1) >= delay(n)with no jitter; jitter in[0, d]; clamp always in[min, max] - 3.7 Co-located
.mdfor each strategy
4. Core retry
- 4.1 Implement
src/retry/retry.ts:sleep(ms, signal?)— cancellable; resolves early on abortretry(fn, config)→Promise<RetryResult<T>>withRetry(fn, config)→Promise<T>— throwsRetryExhaustedErroron exhaustion,RetryErroron abortwithTimeout(fn, ms, signal?)→Promise<T>— throwsAttemptTimeoutErrorcreateDelayFn(strategy)→DelayFunctionwithCircuitBreaker(fn, breaker)→Promise<T>
- 4.2
retryuses injectedclock?: Clockfor sleep duration;rng?: Rngfrom config forwarded to strategy - 4.3
retryhonoursAbortSignalbetween attempts (checks before each delay and after each call) - 4.4 Unit tests: all config options, abort between attempts, timeout, exhaustion,
shouldRetrypredicate - 4.5 Property-based tests:
withRetrynever exceedsmaxAttemptscalls to fn - 4.6 Co-located
src/retry/retry.md
5. Circuit breaker
- 5.1 Implement
src/circuit-breaker/circuit-breaker.ts—CircuitBreakerclass- State machine:
closed → open → half-open → closed(or back to open) .call(fn, signal?)— throwsCircuitOpenErrorwhen open.reset()— force back to closed.stategetter —CircuitState- Event emitter via
@suaveplan/events:stateChangeevent withCircuitBreakerEventMap halfOpenProbesattempts before promoting to closedtimeoutwindow after which open resets to half-open (usesclock?: Clock)
- State machine:
- 5.2 Unit tests: failure threshold transitions, half-open probing, success promotion, manual reset, signal passing, clock injection
- 5.3 Property-based tests: after
failureThresholdconsecutive failures → state is'open' - 5.4 Co-located
src/circuit-breaker/circuit-breaker.md
6. OTel instrumentation
- 6.1 Counter
retry.attempt.totalby outcome label (success / failure / exhausted / aborted) - 6.2 Histogram
retry.attempt.delay_msby strategy label - 6.3 Counter
circuit_breaker.state_change.totalby from/to label - 6.4 Histogram
circuit_breaker.call.duration_ms - 6.5 No-op without exporter (tested)
7. Benchmarks
- 7.1
src/__benchmarks__/sleep.bench.ts—sleep(0)call overhead baseline (mitata) - 7.2
src/__benchmarks__/retry.bench.ts—withRetrywith always-succeeding fn (0-retry overhead) - 7.3
src/__benchmarks__/backoff.bench.ts—createExponentialBackoffdelay computation 1 000 iterations - 7.4
src/__benchmarks__/circuit-breaker.bench.ts—CircuitBreaker.callclosed-state hot path 10 000 iterations - 7.5 Publish baseline numbers in README
8. Docs
- 8.1 Co-located
.mdfor every implementation file (≥200 words, examples, API reference) - 8.2 Rewrite
README.mdwith public API, circuit breaker state diagram, strategy comparison table, consumer guide - 8.3
bun run docs:check --filter=@suaveplan/retry≥ 90%
9. Verify and publish
- 9.1
bunx turbo lint typecheck test --filter=@suaveplan/retrygreen - 9.2
bunx turbo test:coverage --filter=@suaveplan/retryat 100/100/100/100 - 9.3
bunx turbo build --filter=@suaveplan/retrygreen - 9.4
bun scripts/publish.ts --package @suaveplan/retryto Verdaccio at 0.0.0 - 9.5 Archive OpenSpec change to
openspec/archive/2026-04-18-enterprise-retry/