Backend coding interview

Concurrent Bank Transfer Coding Problem

ConcurrencyDeadlock preventionMedium

What this interview round tests

Money-transfer problems are a staple of backend interviews because they force you to reason about several hard things at once: atomicity, deadlocks, race conditions, and idempotency. They are especially common in SDE2 rounds and at fintech and payments companies, where getting concurrency wrong means lost or duplicated money.

This is not a data-structures question. It tests whether you can take a service that looks correct on a single thread and make it correct when many transfers run in parallel — including two transfers that touch the same two accounts in opposite directions.

The scenario

You’re maintaining a backend service that moves money between accounts. A transfer debits a source account and credits a destination account, and every transfer is recorded in a ledger. The happy path already works when requests arrive one at a time.

Under concurrency it breaks. Two opposing transfers — A to B and B to A — can deadlock waiting on each other’s locks. The balance check can happen at the wrong moment, so an account can be overdrawn or a failed transfer can leave partial changes behind. Retried requests can apply the same transfer twice. Your job is to make transfers atomic, deadlock-free, and safe to retry.

What you’ll practice

  • Atomic transfers: keeping the balance check and both mutations in one critical section
  • Deadlock prevention via a stable global lock order (always lock the lower account id first)
  • Race conditions: validating funds before debiting, never the other way around
  • Transaction integrity: a failed transfer leaves both accounts and the ledger unchanged
  • Idempotency: an early key lookup plus a re-check so a retry never double-applies
  • Correct request validation and consistent transfer history on both accounts

How to approach it

The deadlock fix is lock ordering: whenever a transfer needs both account locks, acquire them in a stable order based on account id so no A-waits-for-B / B-waits-for-A cycle can form — and do it without collapsing everything onto one global lock.

Inside that critical section, re-check the idempotency key, confirm both accounts exist and are active, verify the source has sufficient funds before debiting, move the money, and write exactly one completed ledger entry. Validate the request shape (reject same-account and non-positive amounts) up front so bad input never reaches the money-moving path.

The starter repository ships with a failing test suite and a bundled verify.sh. Reviewed reference solutions are part of Gronex Pro — this page stays spoiler-free on purpose.

Try it in a real repository

LeetCode teaches algorithms. Gronex teaches backend coding rounds with real repositories, failing tests, service logic, and production-style constraints. Open the brief and read the full problem — no signup required.

FAQ

Why is a bank transfer a classic concurrency interview problem?

It bundles the hardest concurrency topics into one realistic task: atomicity, deadlock prevention, race conditions, and idempotency. That makes it a favourite for SDE2 and fintech backend interviews.

How do you prevent deadlock between two transfers?

Acquire the two account locks in a stable global order — for example, always lock the account with the lower id first — so opposing transfers can never form a waiting cycle. Doing this without one big global lock is the point of the exercise.

What does idempotency have to do with transfers?

Networks retry. If the same transfer request arrives twice, it must apply exactly once. You practice an early idempotency-key lookup plus a re-check inside the critical section so a retry returns the original result instead of moving money again.

Related