tezvyn:

Design an automated 3-email onboarding sequence with early exit

AI-drafted, machine-checkedintermediate

Tests distributed state management and reliable delayed execution. A good design uses an idempotent state field, scheduled jobs with at-least-once delivery, and an event handler to suppress sends on conversion.

WHAT THIS TESTS: The interviewer wants to see if you treat email sequences as a state machine rather than a script. At senior level they care about observability, failure recovery, and exactly-once send guarantees without distributed transactions.

A GOOD ANSWER COVERS: First, model the user with an explicit onboarding_state field such as signed_up, email_1_sent, email_2_sent, completed, or unsubscribed. Keep this in the primary user record or a dedicated onboarding table so every worker reads the same source of truth. Second, schedule delays with a job queue that supports future visibility, such as SQS with delay seconds, BullMQ with cron, or a workflow engine like Temporal. Emit a job for each email at its offset, for example 0 hours, 24 hours, and 72 hours after signup. Third, implement early exit by listening to a key action event, such as profile_completed or first_purchase. The handler should atomically transition the state to completed and either delete pending jobs from the queue or write a suppress_send flag that send workers check immediately before calling the email provider. Fourth, make every send handler idempotent by checking state or using a sent_log table with unique constraints on user_id plus email_template so that duplicate jobs caused by retries never double-send.

COMMON WRONG ANSWERS: A red flag is proposing a single cron job that runs every hour and queries for users where signup_time is between 23 and 25 hours ago. This creates a thundering herd, misses users who signed up during downtime, and makes it hard to know whether an email was already sent. Another red flag is storing sequence progress only in Redis without a durable backing store; if the cache restarts you lose track and may restart the sequence. Saying you will use a distributed lock for everything is also a warning sign because it suggests you are fighting symptoms instead of designing for idempotency.

LIKELY FOLLOW-UPS: The interviewer may ask how you handle a third-party email provider outage. You should answer that jobs stay in the queue with exponential backoff and dead-letter after a threshold. They may also ask about A/B testing subject lines; a good response is to assign a variant at signup time and store it with the state so the same variant is used for all three emails. They might ask about analytics; mention an outbox pattern where you record the send intent before calling the API so you can reconcile drops.

ONE CONCRETE EXAMPLE: Imagine a user signs up at 9:00 AM. The signup handler writes onboarding_state equals signed_up and enqueues three jobs with delays of 0, 86400, and 172800 seconds. At 9:05 AM the user completes the key action. The action handler updates onboarding_state to completed and publishes a cancellation event. The second and third jobs still fire later, but each send worker checks the state at 9:05 AM the next day, sees completed, and exits without calling the provider. If the first email job fails mid-flight and retries, the sent_log table blocks the duplicate because the first attempt already succeeded.

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.