Architecture
System Context
The Subscription Service is a set of AWS Lambda functions behind the site-subscription-service API Gateway (AWS_IAM authorization). It consumes membership lifecycle events from the User Service and ACH payment outcomes from the Payments Service (both via Kinesis), runs scheduled collection and notification passes from EventBridge rules, reacts to balance events from the Transactions Service, and publishes billing activity changes to the site-subscriptions Kinesis stream.
Components
Runtime configuration (memory, timeout, IAM) is in Infrastructure; queue and schedule detail in SQS Queues and EventBridge.
| Component | Trigger | Purpose |
|---|---|---|
|
API Gateway |
REST API — activation, reactivation, upgrade/downgrade, manual pay, billing history and details, active term, ban, QA create |
|
Kinesis |
Drives subscription state transitions from membership lifecycle events — Membership Events |
|
Kinesis |
Maps ACH payment outcomes to billing status transitions; emits user notifications — ACH Processing |
|
DynamoDB Stream on |
Publishes change records to the |
|
SQS |
Bulk subscription operations dispatched to the batch queue |
|
EventBridge rules (Mon–Fri: scheduled, retry, pause) + SQS paging queues |
Queries |
|
SQS |
Executes collection attempts via the Payments Service; applies the ML decider; advances billing status |
|
SQS |
Opportunistic collection on |
|
EventBridge |
Enqueues users approaching their billing date to the notifier-worker queue — Notifications |
|
SQS |
Sends pre-subscription notifications via Iterable |
The repository also builds the subscription-jobs container image for scheduled batch jobs intended to run as ECS Fargate tasks rather than Lambdas — see Container Images. Job implementations build on the generic batch runner in pkg/jobs: an up-front candidate load fanned through a rate-limited worker pool, per-run counters, DogStatsD job metrics (subscriptions.job.*, filtered by the job: tag), and an in-place-updating Slack run report with breakdown and error-summary thread replies. Per-record errors and panics are counted and reported but never fail the run.
Components that mutate subscription state acquire a per-user distributed lock first — collections-worker, batch-worker, webhook-balance-worker, the memberships handlers (except CLOSEACCOUNT), and manual pay in the api Lambda; the ach-handler writes settlement outcomes without it (locks table).
External Dependencies
| Service | Role |
|---|---|
Payments Service |
Executes collection attempts (collections-worker, webhook-balance-worker, manual pay); source of the ACH outcome callbacks on |
User Service |
User profile lookups (API, memberships, notifier-worker); source of the membership event stream |
Underwriting Service |
Recalculation triggered by manual pay |
Transactions Service |
Bank balance lookups for collection decisions; source of the balance events behind the webhook-balance-worker |
Admin Service |
Admin notes attached by the ach-handler on certain ACH outcomes |
GrowthBook |
Feature flags gating collection, pricing, and notification behavior — GrowthBook Flags |
SageMaker |
|
EventBridge |
Scheduled collection and notifier rules; balance-event routing into the tap queue |
Segment |
Analytics events from the ach-handler, collections-worker, and webhook-balance-worker |
Iterable |
Email and in-app notifications from the ach-handler and notifier-worker |
AppsFlyer |
Mobile attribution events from the ach-handler and webhook-balance-worker |
Storage schemas and access patterns are in DynamoDB Tables; collection decision logic is in Collections Engine.