Code Review: Partial Failure in a Java Payment Method That Charges Then Records
Company: Mercor
Role: Software Engineer
Category: Software Engineering Fundamentals
Difficulty: medium
Interview Round: Technical Screen
The interviewer shows the following Java service, which charges a user through an external payment provider and then records the payment in a database. The question: what happens if the client fails in the middle of the call, and how would you change the code? There is no coding in this round; explain the problems and your fix.
```java
import java.util.Map;
public class PaymentService {
private final PaymentProvider provider;
private final Database db;
public Map<String, String> createPayment(String userId, int amountCents) {
// calls external provider (e.g., Stripe-like)
String chargeId = provider.charge(userId, amountCents);
db.insert("payments", Map.of(
"user_id", userId,
"amount", amountCents,
"charge_id", chargeId
));
return Map.of("status", "ok", "charge_id", chargeId);
}
}
```
Assume `provider.charge` makes a network call that charges the user and returns the provider's charge ID, throwing an exception on failure, and that `db.insert` writes one row.
```hint Walk the timeline
List each point at which a process or a network connection could fail during this method, and write down the state of the provider and of the database at each point.
```
```hint Retries will happen
Assume the caller times out and sends the same request again. Decide what would let the system recognize the second request as the same purchase.
```
### Clarifying Questions
- Who is "the client" here: the caller of `createPayment` (an app or another service that retries on timeout), or this service's own connection to the provider?
- Does the provider accept an idempotency key, or let us look up a charge by a reference we supply?
- What should the caller be told when the outcome of a charge is unknown?
- Can the caller send a unique ID for each purchase attempt?
### What a Strong Answer Covers
- The failure points between and around the two calls, and the inconsistent states each one leaves (charged but unrecorded, charged twice, unknown outcome)
- Why a database transaction around both calls does not make them atomic
- Idempotency: a key per purchase attempt, a uniqueness constraint, and passing the key to the provider
- Recording the attempt before the external call, explicit payment states, and reconciliation of stuck or unmatched payments
- Honest responses for declines and unknown outcomes, plus the other review issues visible in the snippet
### Follow-up Questions
- The provider call times out and you do not know whether the user was charged. What does your code do, and what does the caller see?
- The provider does not support idempotency keys. How do you prevent double charges?
- How would you find and repair payments that were charged at the provider but never recorded?
- Why not simply wrap the provider call and the insert in one database transaction?
Overview: A Java code-reading question about a payment method that charges an external provider and then inserts a database record, focused on what happens when the client fails in the middle of the call. It tests reasoning about partial failures, retries, idempotency keys, payment states, and reconciliation with the provider.
Read the full Mercor Software Engineer interview experience this question came from