PracHub
QuestionsPremiumCoachesLearningGuidesInterview Prep

Quick Overview

This question evaluates skills in deterministic workflow design, idempotency and retry-safety for external payment integrations, state-transition correctness, and unit testing for edge cases such as timeouts and duplicate execution.

  • medium
  • DoorDash
  • Coding & Algorithms
  • Software Engineer

Implement Timeout Refund Workflow

Company: DoorDash

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: medium

Interview Round: Onsite

You are given a skeleton workflow engine for order processing. A workflow is a directed graph of nodes. Each node receives an `OrderContext` and returns the id of the next node to execute, or `null` to stop. Implement the missing node logic for refunding orders that have timed out. Data model: - `Order`: `order_id`, `created_at`, `status` with values `PENDING`, `COMPLETED`, `CANCELED`, or `REFUNDED`, `amount_cents`, and `refunded_cents`. - `OrderContext`: the order, `now`, and an append-only list of emitted events. - `PaymentClient.refund(order_id, amount_cents, idempotency_key)`: issues a refund and may return success or a retryable failure. Required nodes: 1. `TimeoutDecisionNode`: if an order is still `PENDING` and `now - created_at >= timeout_minutes`, route to `refund`; otherwise route to `end`. 2. `RefundNode`: issue a full refund exactly once, update the order to `REFUNDED`, append a `REFUND_ISSUED` event, and route to `end`. 3. `EndNode`: stop execution. Requirements: - The workflow should be deterministic and safe to retry. - Use idempotency keys so the same order is not refunded twice. - Keep node implementations small and easy to add to the graph. - Write unit tests for the not-timed-out path, timed-out refund path, completed-order path, retry path, and duplicate-execution path. Follow-ups: - Add a `PartialRefundNode` that refunds a percentage or fixed amount. - Add a `CancelNode` for timed-out orders where payment has not been captured. - Explain how you would limit code changes when using an AI coding assistant and how you would review generated code before accepting it.

Quick Answer: This question evaluates skills in deterministic workflow design, idempotency and retry-safety for external payment integrations, state-transition correctness, and unit testing for edge cases such as timeouts and duplicate execution.

You are implementing the node logic for a small deterministic order-processing workflow engine. A workflow is a directed graph of nodes. Each node receives the current order context and returns the id of the next node to execute, or stops at the end node. For this problem, an order is represented as a dictionary with keys: `order_id`, `created_at`, `status`, `amount_cents`, and `refunded_cents`. Time values are integer minutes. Implement the workflow behavior inside `solution`. To make retry and duplicate execution testable, `solution` should execute the same workflow `runs` times against the same persisted order context. Each run starts at the timeout decision node. Required nodes: 1. `TimeoutDecisionNode`: If the order status is still `PENDING` and `now - created_at >= timeout_minutes`, route to `refund`; otherwise route to `end`. 2. `RefundNode`: Issue the remaining full refund exactly once. Use the idempotency key `refund:<order_id>:full`. If the mock payment result is success, update the order to `REFUNDED`, set `refunded_cents` to `amount_cents`, append one `REFUND_ISSUED` event, and route to `end`. If the result is a retryable failure, do not update the order and do not append an event, so a later run may retry using the same idempotency key. 3. `EndNode`: Stop execution. The mock payment client is represented by `payment_results`, a list of booleans. A refund attempt consumes the next boolean: `True` means success, and `False` means retryable failure. If no result is available, treat the attempt as a retryable failure. The workflow must be deterministic and safe to retry. Once a refund has succeeded, duplicate workflow executions must not issue another refund call. Follow-up discussion prompts: add a `PartialRefundNode`, add a `CancelNode` for uncaptured payments, and explain how you would constrain and review AI-generated code changes.

Constraints

  • `status` is one of `PENDING`, `COMPLETED`, `CANCELED`, or `REFUNDED`.
  • `0 <= created_at <= now <= 10^12`.
  • `1 <= timeout_minutes <= 10^9`.
  • `0 <= refunded_cents <= amount_cents <= 10^12`.
  • `0 <= runs <= 1000`.
  • `payment_results` contains booleans; values are consumed only when a refund call is actually attempted.

Examples

Input: ({'order_id': 'o1', 'created_at': 100, 'status': 'PENDING', 'amount_cents': 2500, 'refunded_cents': 0}, 119, 20, [True], 1)

Expected Output: {'order': {'order_id': 'o1', 'created_at': 100, 'status': 'PENDING', 'amount_cents': 2500, 'refunded_cents': 0}, 'events': [], 'refund_calls': []}

Explanation: The order is pending, but only 19 minutes have passed, which is less than the 20 minute timeout. The workflow routes directly to end.

Input: ({'order_id': 'o2', 'created_at': 100, 'status': 'PENDING', 'amount_cents': 3000, 'refunded_cents': 0}, 130, 30, [True], 1)

Expected Output: {'order': {'order_id': 'o2', 'created_at': 100, 'status': 'REFUNDED', 'amount_cents': 3000, 'refunded_cents': 3000}, 'events': [['REFUND_ISSUED', 'o2', 3000, 'refund:o2:full']], 'refund_calls': [['o2', 3000, 'refund:o2:full', 'SUCCESS']]}

Explanation: This is the boundary case: exactly 30 minutes have passed, so the order has timed out. The refund succeeds and one refund event is emitted.

Input: ({'order_id': 'o3', 'created_at': 0, 'status': 'COMPLETED', 'amount_cents': 4500, 'refunded_cents': 0}, 1000, 30, [True], 1)

Expected Output: {'order': {'order_id': 'o3', 'created_at': 0, 'status': 'COMPLETED', 'amount_cents': 4500, 'refunded_cents': 0}, 'events': [], 'refund_calls': []}

Explanation: Even though the order is older than the timeout, it is already COMPLETED, not PENDING, so no refund is attempted.

Input: ({'order_id': 'o4', 'created_at': 0, 'status': 'PENDING', 'amount_cents': 2000, 'refunded_cents': 0}, 60, 30, [False, True], 2)

Expected Output: {'order': {'order_id': 'o4', 'created_at': 0, 'status': 'REFUNDED', 'amount_cents': 2000, 'refunded_cents': 2000}, 'events': [['REFUND_ISSUED', 'o4', 2000, 'refund:o4:full']], 'refund_calls': [['o4', 2000, 'refund:o4:full', 'RETRYABLE_FAILURE'], ['o4', 2000, 'refund:o4:full', 'SUCCESS']]}

Explanation: The first run attempts the refund but receives a retryable failure, so the order remains PENDING. The second run retries with the same idempotency key and succeeds.

Input: ({'order_id': 'o5', 'created_at': 0, 'status': 'PENDING', 'amount_cents': 999, 'refunded_cents': 0}, 60, 30, [True, True], 2)

Expected Output: {'order': {'order_id': 'o5', 'created_at': 0, 'status': 'REFUNDED', 'amount_cents': 999, 'refunded_cents': 999}, 'events': [['REFUND_ISSUED', 'o5', 999, 'refund:o5:full']], 'refund_calls': [['o5', 999, 'refund:o5:full', 'SUCCESS']]}

Explanation: The first run succeeds. The second run is a duplicate execution, but the order is already REFUNDED, so no second payment call is made.

Hints

  1. Represent each workflow node as a small function that returns the next node id, then loop until the end node stops execution.
  2. Before calling the payment client, check persisted order state and emitted refund events. The idempotency key should be stable and derived only from the order and refund type.
Last updated: Jun 13, 2026

Loading coding console...

PracHub

Master your tech interviews with 8,000+ real questions from top companies.

Product

  • Questions
  • Learning Tracks
  • Interview Guides
  • Resources
  • Premium
  • For Universities
  • Student Access

Browse

  • By Company
  • By Role
  • By Category
  • Topic Hubs
  • SQL Questions
  • Compare Platforms
  • Discord Community

Support

  • support@prachub.com
  • (916) 541-4762

Legal

  • Privacy Policy
  • Terms of Service
  • About Us

© 2026 PracHub. All rights reserved.

Related Coding Questions

  • Validate a Shopping Cart - DoorDash (medium)
  • Calculate Driver Payments - DoorDash (medium)
  • Maximize Chef Assignment Profit - DoorDash (medium)
  • Compute Courier Delivery Pay - DoorDash (easy)
  • Compute Nearest Destination Distances - DoorDash (easy)