Engineering Playbook • Subscriptions

Subscription Event Handling: Design Patterns and Best Practices

Handle subscription lifecycle events (created, updated, deleted) with idempotent, state-aware logic. Process only resources that need changes, and track subscription status separately from resource status.

State-aware updates Idempotent workflows Clear audit trails

Overview

Subscription events are noisy: retries, out-of-order delivery, and status transitions all happen in production. The safest posture is to treat every event as a diff, only touching resources that actually need a change.

This guide lays out concrete handling rules for created, updated, and deleted events, with implementation patterns, rationale, and an architecture that scales with retry storms.

Quick rules

  • Created: Activate only PENDING resources and set subscription to active.
  • Updated: Reactivate SUSPENDED resources when status is active/trialing.
  • Updated: Suspend only ACTIVE resources when status is past_due/unpaid.
  • Deleted: Mark subscription canceled; leave resources as-is.
Rule 1

Subscription Created Event

Principle: Only activate pending resources

  • Process only resources in a PENDING state; ignore others.
  • Set the subscription status to active.
  • Clear any suspension timestamps.
  • Trigger activation workflows (deployments, provisioning, etc.).

Rationale

  • Prevents duplicate activations.
  • Handles renewals and re-subscriptions without affecting active resources.
  • Ensures a clean start for new subscriptions.

Implementation pattern

IF subscription.created:
  FOR EACH resource IN user_resources:
    IF resource.status == PENDING:
      → Activate resource
      → Trigger activation workflow
    ELSE:
      → Skip (already active or in different state)
  SET subscription.status = 'active'
  CLEAR subscription.date_suspended
Rule 2

Subscription Updated Event

Principle: Reactivate suspended or suspend active based on new status

If status is active or trialing

  • Reactivate only resources that are SUSPENDED.
  • Set subscription status to active.
  • Clear suspension timestamps.

Rationale

  • Avoids unnecessary operations.
  • Supports reactivation after payment issues.

If status is past_due, unpaid, etc.

  • Suspend only resources that are ACTIVE.
  • Set subscription status to suspended.
  • Record suspension timestamp (if not already set).

Rationale

  • Tracks suspension duration for business rules.
  • Prevents double-suspends on retries.

Implementation pattern

IF subscription.updated:
  IF new_status IN ['active', 'trialing']:
    FOR EACH resource IN user_resources:
      IF resource.status == SUSPENDED:
        → Reactivate resource
        → Trigger reactivation workflow
    SET subscription.status = 'active'
    CLEAR subscription.date_suspended
  ELSE:  // past_due, unpaid, etc.
    FOR EACH resource IN user_resources:
      IF resource.status == ACTIVE:
        → Suspend resource
        → Trigger suspension workflow
    SET subscription.status = 'suspended'
    IF subscription.date_suspended IS NULL:
      SET subscription.date_suspended = NOW()
Rule 3

Subscription Deleted Event

Principle: Mark as canceled, preserve resource state

  • Clear the subscription ID.
  • Set subscription status to canceled.
  • Do not change resource statuses; leave them as-is (typically suspended).

Rationale

  • Preserves data for audit and recovery.
  • Allows manual cleanup or grace periods.
  • Avoids accidental data loss.

Implementation pattern

IF subscription.deleted:
  CLEAR subscription.subscription_id
  SET subscription.status = 'canceled'
  // DO NOT modify resource statuses
  // Resources remain in their current state (typically SUSPENDED)
  // Manual cleanup or scheduled jobs can handle final deletion

Key design principles

  1. State-aware processing: Only modify resources that need changes. Check current state before acting.
  2. Idempotency: Events can be processed multiple times safely. Use idempotency keys or state checks.
  3. Separation of concerns: Subscription status tracks payment state, resource status tracks operational state.
  4. Graceful degradation: If activation fails, log errors but do not crash; retry later.
  5. Audit trail: Track suspension dates, status changes, and event processing for debugging.

Common pitfalls to avoid

  • Processing all resources regardless of state.
  • Auto-deleting resources on cancellation.
  • Not tracking suspension dates.
  • Ignoring event order or retries.
  • Not validating subscription status before processing.

Recommended architecture

Keep event handling predictable by sequencing validation, actions, and metadata updates. The flow below makes retries safe and isolates failures.

Webhook Receiver
    ↓
Event Router (created / updated / deleted)
    ↓
State Validator (check current resource states)
    ↓
Action Executor (activate / suspend / reactivate)
    ↓
Status Updater (update subscription metadata)
    ↓
Workflow Trigger (async jobs for provisioning)