Design a Stateful Outreach Campaign Engine
OscarSoftware Engineer · Technical ScreenLast updated
This problem tests the ability to design a resilient, stateful task scheduler capable of handling asynchronous external triggers (responses) and idempotent state transitions.
Design a Stateful Outreach Campaign Engine
Design a backend service that manages automated outreach campaigns for healthcare clients. A campaign consists of a sequence of messages (Email, SMS) sent at specific intervals (e.g., T+0, T+24h, T+72h). The system must stop the sequence immediately if the user replies or if the client cancels the campaign.
Requirements
Functional Requirements:
- Campaign Sequences: Support a series of scheduled messages per user contact.
- Stop Condition: Cancel all future scheduled tasks for a user if they reply or if the client cancels the campaign.
- Durable State: Track the current status of each campaign (e.g., PENDING, COMPLETED, CANCELLED, STOPPED_BY_RESPONSE).
- Failure Handling: Retry transient failures (e.g., 5xx errors from email/SMS providers) with exponential backoff.
Non-Functional Requirements:
- Scale: Handle up to 100,000 active campaigns with varying schedules.
- Concurrency: Ensure that a race condition between a scheduled task and an incoming user response does not lead to duplicate messages.
- Observability: Track message delivery status and provide an audit log of all state transitions.
Deliverables
- Data Model: Define the database schema for campaigns, individual message tasks, and the user response log.
- API Design: Provide the endpoints to start a campaign and register a user response.
- Architecture: Describe the high-level design. How do you handle scheduling tasks in the future? How do you ensure idempotent processing of events?
- Trade-offs: Discuss how you would handle 'out-of-order' events, such as a reply arriving just as a message is being dispatched.
Hints
Hint 1
Consider using a delayed job queue or a dedicated scheduling service rather than a simple polling database.
Hint 2
Think about using a state machine per campaign to transition between states and prevent race conditions when a reply arrives simultaneously with a send job.
Hint 3
Use idempotent operation keys (e.g., request IDs or task hashes) to ensure that retrying a failed delivery attempt does not result in duplicate messages.
Follow-up questions
- How would you handle a scenario where a third-party SMS provider experiences a massive outage for several hours?
- If the business requirements change to allow 'dynamic pauses' in the campaign based on the time of day, how would you update your scheduler?
- How would you implement a 'dead-letter queue' for messages that consistently fail to reach the user?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.