Implement held transfers with accept/cancel
MetaSoftware Engineer · Online AssessmentLast updated
This interview question evaluates requirements, scale assumptions, API/data design, architecture, trade-offs, failure modes, and rollout in a realistic interview setting. A strong answer for Implement held transfers with accept/cancel states assumptions, handles edge cases, explains trade-offs, and shows how to validate the result clearly.
Question
Design and implement a two-phase ("pull-style") money-transfer system in which funds are first held on the source account and then either captured or released. The transfer is created by the source; the target decides whether to accept it; either party may cancel while it is still pending.
Implement the following operations:
String transfer(long timestamp, String targetAccountId, int amount)— create a transfer, place a hold on the source account's funds, and return a uniquetransferId.boolean accept(long timestamp, String accountId, String transferId)— finalize the transfer: move the held funds from the source to the target (accountIdmust be the target).boolean cancel(long timestamp, String accountId, String transferId)— release the hold and fully restore the source account's availability.
In your design and write-up, address:
- Balance semantics: clearly distinguish the ledger (posted) balance from the available balance, and show how a hold affects each on the source and target accounts.
- State machine: define the legal transfer states (e.g.
PENDING → ACCEPTED | CANCELED, plus an optionalEXPIRED) and the allowed transitions; terminal states are final. - Data structures: maintain
allTransfersandpendingTransfersin hash maps (not lists) so that lookups and state changes are O(1). Track per-account hold totals incrementally instead of scanning lists. - Authorization: only the target may
accept; the source or the target maycancelwhile pending. - Idempotency & duplicate requests: define behavior for repeated
accept/cancel, for an optional client idempotency key ontransfer, and for an unknown/invalidtransferId. - Atomicity & concurrency: how balance, hold, and transfer-state updates are made atomic (per-account locks, deterministic lock ordering to avoid deadlock).
- Expiration (TTL): optional hold expiry using
timestamp— how an expired pending transfer is auto-released and howaccept/cancelbehave against it. - Failure recovery & durability: how to keep the system consistent across crashes (ACID transaction, WAL/outbox, background reconciler/sweeper).
- Error handling: invalid
transferId, wrong actor, insufficient funds, non-positive amount, self-transfer. - Complexity: give the time and space complexity of each operation.
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.