Build a Three-Service Refund Workflow over HTTP
Company: DoorDash
Role: Software Engineer
Category: Software Engineering Fundamentals
Difficulty: medium
Interview Round: Technical Screen
## Build a Three-Service Refund Workflow over HTTP
For this exercise, build three independently running local services:
- **Order Service** owns order data and exposes a read endpoint.
- **Refund Service** accepts an idempotent refund request and records its result.
- **Workflow Service** receives a refund command and executes a directed acyclic graph with the steps `fetch order -> validate eligibility -> submit refund`.
The services must listen on different local ports and communicate through real HTTP requests. Calling classes in the same process or replacing every dependency with an in-memory method does not satisfy the exercise.
### Part 1 — Define the HTTP Contracts
Specify request and response shapes, identifiers, status codes, and idempotency behavior for reading an order, starting a workflow, checking workflow state, and submitting a refund.
#### What This Part Should Cover
- Stable `order_id`, `workflow_id`, and `refund_id` semantics.
- An amount in integer minor units plus currency rather than a floating-point money value.
- Validation and clear client-error versus server-error responses.
- A caller-supplied refund idempotency key.
```hint Name the business actions before choosing routes
First identify which calls read state, create a workflow, and create one logical refund.
```
### Part 2 — Execute and Persist the DAG
Model step dependencies and durable workflow state. Explain how a worker finds ready steps, records attempts, avoids running a completed step twice, and marks the workflow complete or failed.
#### What This Part Should Cover
- Explicit nodes, dependencies, and per-node state.
- Durable transitions rather than process-memory-only progress.
- Idempotent step execution and restart after a crash.
- Separation of business rejection from retryable infrastructure failure.
```hint Persist before crossing a service boundary
Consider what state must exist if the process dies immediately after the Refund Service accepts a request.
```
### Part 3 — Run the Services Locally
Describe a minimal way to start all three processes, configure their base URLs, verify readiness, and demonstrate one successful end-to-end HTTP workflow.
#### What This Part Should Cover
- Separate processes or containers with distinct ports.
- Configuration through environment or launch arguments rather than hard-coded production addresses.
- Health or readiness checks and a reproducible startup command.
- Evidence from HTTP responses and service logs that network calls occurred.
```hint Prove the process boundary
A passing unit test over three classes does not show that serialization, routing, ports, or timeouts work.
```
### Part 4 — Handle Failure and Concurrency
Address dependency timeouts, a duplicate workflow request, two concurrent refunds for one order, and a crash after refund acceptance but before the workflow records success.
#### What This Part Should Cover
- Bounded timeouts and retry policy per HTTP call.
- Stable idempotency keys reused after ambiguous outcomes.
- A concurrency rule preventing the refundable balance from being exceeded.
- Logs and traces correlated by workflow and refund identifiers.
```hint Treat a timeout as unknown outcome
After sending a refund request, no response does not prove that the Refund Service rejected it.
```
### What a Strong Answer Covers
- Produces a genuinely networked three-service implementation, not a single-process simulation.
- Makes workflow progress durable and restartable.
- Defines money, identifiers, errors, and idempotency precisely.
- Protects refund limits under retries and concurrent requests.
- Includes a short, reproducible end-to-end demonstration.
### Follow-up Questions
1. Where should refund eligibility be authoritative if order data can change during the workflow?
2. How would you add a second refund approval step without hard-coding a new execution path?
3. What should the Workflow Service return while a long-running workflow is still pending?
4. Which integration test catches a refund that committed just before an HTTP timeout?
Quick Answer: Build three separately running HTTP services for orders, refunds, and a durable refund workflow expressed as a dependency graph. The exercise tests real process boundaries, money and API contracts, idempotent steps, restart recovery, concurrent refund limits, timeout ambiguity, and reproducible integration evidence.