How Cadence Works

Cadence tracks failures for a unique key. A key can represent anything you want to protect, such as:

  • A user ID
  • An email address
  • An IP address
  • An API token
  • A webhook identifier

Failure Tracking Flow

Each failed attempt increases the recorded attempt count for that key.

Once the configured free-attempt threshold has been exceeded, Cadence temporarily locks the key using the configured backoff strategy.

While the key is locked, calling ensureNotLocked() throws a CadenceLockedException.

Calling recordSuccess() clears the recorded failures and immediately removes any active lock.

Lifecycle

  1. Initial State - No failures recorded for the key
  2. Free Attempts - Failures are recorded but no delay is applied (up to free_attempts)
  3. Backoff Applied - After exceeding free attempts, delays increase progressively
  4. Lock Active - ensureNotLocked() throws CadenceLockedException
  5. Success Recorded - All failure state is cleared, key is unlocked
  6. Idle Timeout - After idle_timeout seconds, failure state expires naturally

State Persistence

Cadence stores its state using Laravel's cache abstraction. This means:

  • State persists across requests
  • State can be shared across multiple application instances
  • State respects the configured cache store and TTL
  • State expires after the configured idle_timeout