Skip to content
mittr

Retry Strategies

Mittr automatically retries failed deliveries with configurable backoff, circuit breakers, and rate limiting.

Each endpoint has its own retry configuration:

SettingDefaultDescription
maxRetries5Maximum delivery attempts
retryBackoffMs1000Initial backoff (1 second)
retryBackoffMax86400000Maximum backoff (24 hours)
retryBackoffMult2.0Exponential multiplier
timeoutMs30000HTTP request timeout (30 seconds)

Mittr’s default schedule is a fixed sequence covering a full day, front-loaded so transient failures recover quickly:

Attempt 1: 1 second
Attempt 2: 5 seconds
Attempt 3: 30 seconds
Attempt 4: 2 minutes
Attempt 5: 10 minutes
Attempt 6: 30 minutes
Attempt 7: 1 hour
Attempt 8: 2 hours
Attempt 9: 6 hours
Attempt 10: 24 hours → dead letter if all fail

Each delay includes ~10% random jitter to avoid thundering-herd on a destination that recovers all at once.

Per-event override: set maxAttempts when creating an event to cap attempts at a smaller number for less-critical events.

The defaults above kick in when an endpoint doesn’t set its own backoff. If you set retryBackoffMs, retryBackoffMult, and retryBackoffMax on an endpoint, the engine switches to a classical exponential curve for that endpoint only:

delay = min(retryBackoffMs * (retryBackoffMult ^ attempt), retryBackoffMax)

Mixing both is supported per-endpoint — use defaults for most, and override only where you have a reason (e.g. a fast-recovering internal service might want a short, tight curve).

Per-endpoint circuit breakers prevent hammering a failing destination:

SettingDefaultDescription
circuitThreshold5Consecutive failures to open circuit
circuitResetMs60000Recovery check interval (60 seconds)
  • Closed — normal delivery. Failures increment the counter.
  • Open — after circuitThreshold consecutive failures, the circuit opens. Deliveries are queued but not attempted. This protects both Mittr and the destination.
  • Half-open — after circuitResetMs, one test delivery is attempted. If it succeeds, the circuit closes. If it fails, the circuit re-opens for another reset interval.
Closed → (5 failures) → Open → (5 min) → Half-open → success → Closed
→ failure → Open
queued → delivering → delivered (success)
→ failed (retryable, scheduled for next attempt)
→ dead (max retries exhausted, permanent failure)
StatusMeaning
queuedWaiting to be picked up by a worker
deliveringCurrently being sent
deliveredSuccessfully delivered (HTTP 2xx response)
failedDelivery failed, retry scheduled
deadAll retries exhausted, permanently failed

After all retries are exhausted, events move to dead status. Dead events can be:

  • Viewed in the dashboard with full attempt history
  • Edited — change destination or payload, then resend: PATCH /api/v1/events/{id}
  • Replayed as-is: POST /api/v1/events/{id}/replay
  • Batch retried by status: POST /api/v1/events/batch/retry

Replay resets the attempt counter and re-queues the event for delivery.

Per-endpoint rate limiting prevents overwhelming destinations:

{ "rateLimitPerSec": 100 }
  • Set to 0 for unlimited (default)
  • Rate-limited deliveries are re-queued with backoff
  • Rate limit is capped by your plan’s maximum (e.g., Free plan: 10 req/s)

Only successful deliveries count toward your monthly message quota. Failed attempts, dead events, and retries do not consume quota. An event that takes 3 attempts to deliver counts as 1 message.