All skills
simota avatar

/weave

@e307415
by shingo imotasimota/agent-skills85 stars
15

Designing workflows and state machines. Use when state transition design, invalid transition detection, Saga patterns, or approval flow design is needed.

Use this Skill: https://skilld.dev/gh/simota/agent-skills/weave

This session only. Nothing lands on disk.

referenceretry-state-machine.md

≈2.4k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Retry State Machine Reference

Purpose: Design retry state machines with exponential backoff, jitter, max-attempt cap, DLQ as terminal state, and idempotency contract. Separates retriable vs non-retriable failure modes and emits a contract that weave (schedule) and Beacon (alerts) can consume.

Scope Boundary

  • weave retry: Retry state machine design (states, transitions, backoff, jitter, DLQ) — this document.
  • weave timeout (elsewhere): TTL / deadline design. Retry and timeout are often paired; design timeout first, then retry inside the timeout envelope.
  • weave compensation (elsewhere): Saga compensation. Retry handles transient failure; compensation handles logical undo.
  • weave (elsewhere): Schedule / cron / backoff curve details. Retry state machine consumes weave's backoff rules.
  • Beacon (elsewhere): SLO / retry-exhaustion alerts.
  • siege concurrency (elsewhere): Race/deadlock analysis on retry implementations.

Workflow

CLASSIFY   →  split failures: retriable (transient) vs non-retriable (logical)
           →  5xx/network/timeout → retriable
           →  4xx/validation/auth → non-retriable (usually)

STATES     →  idle → attempting → waiting → attempting ... → success / DLQ
           →  terminal: success | permanent_failure | dlq

BACKOFF    →  base delay × 2^(attempt-1), capped at max_delay
           →  add jitter: full / equal / decorrelated

CAP        →  max_attempts = f(business SLA, error budget, DLQ capacity)
           →  typical: 3 for user-facing, 5-7 for background, 10+ for async

IDEMPOTENCY → every attempt uses the same idempotency key
           →  server must dedupe; retry state machine never generates a new key mid-retry

DLQ        →  terminal state for exhausted retries
           →  DLQ emits alert + preserves original message for human review

ALERT      →  hand off retry-exhaustion signal to Beacon
           →  hand off DLQ depth alert to Beacon

State Diagram

              ┌──────────┐
              │   idle   │
              └────┬─────┘
                   │ start
                   ▼
              ┌──────────┐       success       ┌──────────┐
              │attempting├─────────────────────►│ success  │ (terminal)
              └────┬─────┘                     └──────────┘
                   │ failure
       non-retri   │    retriable + attempts<max
       ┌───────────┤
       │           ▼
       │      ┌──────────┐
       │      │ waiting  │
       │      │ (backoff)│
       │      └────┬─────┘
       │           │ timer fires
       │           ▼
       │      ┌──────────┐
       │      │attempting│ (attempt++)
       │      └────┬─────┘
       │           │ attempts == max
       │           ▼
       │      ┌──────────┐
       │      │   dlq    │ (terminal, alert)
       │      └──────────┘
       ▼
  ┌──────────────┐
  │permanent_fail│ (terminal, no retry)
  └──────────────┘

Backoff + Jitter

Strategy Formula Use When
Fixed delay = base Simple, never recommended for production retries
Linear delay = base × attempt Rare; prefer exponential
Exponential delay = min(base × 2^(attempt-1), max_delay) Default
Exponential + Full Jitter delay = random(0, min(base × 2^(attempt-1), max_delay)) AWS recommended default
Exponential + Equal Jitter delay = half + random(0, half) where half = exp/2 Less variance than full
Decorrelated Jitter delay = min(cap, random(base, prev_delay × 3)) Best for thundering-herd prevention

Rule: always add jitter. No jitter → synchronized retries → thundering herd after a downstream recovery.

Typical Parameters

Use Case base max_delay max_attempts
User-facing HTTP 100ms 2s 3
Background job 1s 60s 5
Async queue processor 5s 5min 7
Batch / nightly 10s 30min 10
Webhook delivery 30s 24h 15 (spread over days)

Retriable vs Non-retriable Classification

Error Class Rationale
HTTP 429 (rate limit) Retriable Transient, honor Retry-After header
HTTP 500, 502, 503, 504 Retriable Server-side transient
HTTP 408 (timeout) Retriable Usually transient
HTTP 401, 403 Non-retriable Credentials / permissions
HTTP 400, 422 Non-retriable Validation — same input will fail again
HTTP 404 Usually non-retriable Exception: eventual consistency window
Network timeout Retriable Transient
Connection refused Retriable Service restarting
DNS failure Retriable Transient DNS issue
SSL handshake failure Investigate May be config issue
Deserialize failure Non-retriable Schema mismatch
Idempotency conflict Non-retriable Original request likely succeeded

Idempotency Contract

Every retry must use the same idempotency key:

type RetryState = {
  idempotencyKey: string;      // generated ONCE at `idle → attempting`
  attempt: number;             // 1..max_attempts
  lastError: string | null;
  nextAttemptAt: Date | null;
  terminal: 'success' | 'permanent_failure' | 'dlq' | null;
};

Server-side contract:

  • Dedupe by idempotency key within a TTL window (often 24h).
  • Return the original response for duplicate key (same status, same body).
  • If business rule conflicts (e.g., email already sent), return 409 with the original request-id.

DLQ Design

The DLQ terminal state must:

  1. Preserve full payload (not just error).
  2. Record failure cause (last error + attempt history).
  3. Emit alert (Beacon signal — DLQ depth > threshold).
  4. Allow manual replay with idempotency preserved.
  5. Have TTL (typically 7-30 days before archival / purge).

DLQ Alert Thresholds (Beacon)

Signal Threshold Severity
DLQ depth > 10 messages Page HIGH
DLQ depth growing > 1/min for 10 min Page CRITICAL
Single message failing repeatedly across replay Investigation MEDIUM

Output Template

## Retry State Machine: [Name]

### Context
- **Use case**: [HTTP client / queue consumer / webhook / batch]
- **SLA**: [end-to-end deadline]
- **Blast radius on failure**: [customer impact if DLQ]

### Failure Classification
- **Retriable**: [list of error codes / exceptions]
- **Non-retriable**: [list]
- **Ambiguous**: [list + default handling + rationale]

### State Machine
| State | Entry Actions | Exit Transitions |
|-------|--------------|------------------|
| idle | none | start → attempting |
| attempting | increment attempt counter | success → success; non-retriable → permanent_failure; retriable + attempts<max → waiting; retriable + attempts==max → dlq |
| waiting | compute next_delay with jitter | timer → attempting |
| success | emit success event | terminal |
| permanent_failure | emit permanent-failure event | terminal |
| dlq | enqueue to DLQ + alert | terminal |

### Backoff Parameters
- **Strategy**: [Exponential + Full Jitter / ...]
- **base**: [X ms]
- **max_delay**: [X s]
- **max_attempts**: [N]
- **total_time_budget**: [approx. Σ delays, worst case]

### Idempotency
- **Key generation**: [UUID v4 / ULID / hash of payload]
- **Server-side dedup TTL**: [hours]
- **Conflict handling**: [409 response pattern]

### DLQ
- **Storage**: [SQS FIFO / Kafka DLQ topic / DB table]
- **Retention**: [days]
- **Replay mechanism**: [manual / scheduled]

### Alert Integration (Beacon)
- **Retry-exhaustion rate > X%** over 5 min → HIGH
- **DLQ depth > N** → HIGH
- **DLQ growing > M/min** → CRITICAL

### Handoffs
- weave (backoff curve details)
- Beacon (alerts)
- Builder (implementation)
- Triage (DLQ review runbook)

Common Pitfalls

Pitfall Fix
No jitter Always add jitter (full or decorrelated)
Retrying 4xx Classify as non-retriable unless specifically transient
New idempotency key per attempt Generate once, reuse across retries
Unbounded retries Always cap max_attempts
Ignoring Retry-After header Honor server-requested delay
DLQ without alert Alert on DLQ depth + growth rate
Synchronous retry on user request Use async queue for user-facing calls
Retry storming on circuit-breaker close Combine with circuit breaker state

Deliverable Contract

When retry completes, emit:

  • Failure classification table (retriable / non-retriable / ambiguous).
  • State machine (states, transitions, terminal conditions).
  • Backoff + jitter parameters (strategy, base, max_delay, max_attempts, total budget).
  • Idempotency contract (key generation, server dedup TTL, conflict handling).
  • DLQ design (storage, retention, replay).
  • Alert thresholds for Beacon.
  • Handoffs: weave, Beacon, Builder, Triage.

References

  • Amazon Architecture Blog — "Exponential Backoff and Jitter"
  • AWS SDK default retry policy documentation
  • Google SRE Book — Handling Overload
  • Stripe — Idempotency key design
  • RFC 6585 — 429 Too Many Requests
  • Polly (.NET), resilience4j (Java), tenacity (Python) — reference implementations

Source: SKILL.md on GitHub

No alerts13d4 checks · Risk SAFE
  • Gen Agent Trust Hub13d

    The skill 'weave' is a workflow and state-machine design specialist. It provides comprehensive technical guidance and templates for state transitions, Saga patterns, and approval flows. It includes references to Japanese business calendars and official holiday data from trusted sources, alongside recommendations for well-known workflow engines such as Temporal and AWS Step Functions. No malicious patterns, obfuscation, or unauthorized data access were detected.

  • Socket13d

    No alerts

  • Snyk13d

    Risk: LOW · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at e307415. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 days ago.

Activeupdated 2 weeks ago

README badge

README badge for simota/agent-skills/weave