August 28 2025
Resource Concurrency in the Backend Without Scattered Locks
When several flows compete for the same resource, spreading locks everywhere usually hides the problem instead of organizing it.
Andrews Ribeiro
Founder & Engineer
3 min Intermediate Systems
The problem
Much of the contention in a backend is not “abstract concurrency.”
It is a fight over one very concrete resource:
- the same order
- the same balance
- the same slot
- the same file
When that shows up, the team usually reacts like this:
- add one lock here
- another lock there
- one more check in the worker
Soon nobody knows anymore:
- who actually coordinates
- which resource is being protected
- what happens if the lock breaks
Mental model
The useful question is not:
“where do I put a lock?”
The useful question is:
“which resource cannot be changed at the same time without coordination?”
Once that is clear, the solution usually becomes easier to see.
Sometimes it is:
- a lock
- a queue by key
- optimistic control
- compare-and-set
- a database constraint
A lock is only one option.
Simple example
Imagine cancellation and capture of the same payment happening almost at the same time.
If two different flows can:
- capture
- cancel
- refund
then the contested resource is not “the method.”
It is the payment.
That changes the design.
Maybe coordination needs to happen by payment_id, not scattered across three different places.
The common mistake
The common mistake is spreading too much protection and too little responsibility.
Examples:
- a helper acquires a lock with no clear contract
- a worker adds another lock on top
- the database still tries to enforce something on the side
Now the system has duplicated coordination that is hard to explain and even harder to operate.
When something gets stuck, nobody knows which layer owns the rule.
Where coordination usually works better
Most of the time, coordination should live close to the point where the critical decision happens.
That may be:
- in the database, if contention is local and transactional
- in serial processing by key, if the flow is asynchronous
- in optimistic control, if conflicts are rare and cheap to revalidate
What usually fails is hiding the rule in a generic utility.
A lock is also an operational mechanism
If you use a lock, you still need to answer:
- who owns it?
- when does it expire?
- how is it renewed?
- what happens if the process dies?
Without that, a lock is not coordination.
It is just hope with a technical name.
How a senior thinks
Engineers who choose better usually ask:
- which resource is really being contested?
- is the conflict frequent or rare?
- does the decision need to be synchronous, or can it be serialized later?
- which mechanism makes the behavior easier to explain and recover?
Those questions usually lead to a better design than “add a distributed lock.”
Interview angle
This topic shows up in backend, payments, inventory, queues, and system design.
The interviewer wants to see whether you understand:
- that contention needs a clear owner
- that a lock is not the automatic answer
- that coordination and recovery go together
A strong answer often sounds like this:
“I would first model which resource is actually being contested and where the critical decision happens. From there I would choose between a lock, a queue by key, or optimistic control. The goal is not to spread protection everywhere. It is to centralize coordination in the right place.”
Direct takeaway
Mature concurrency is not about locking everything.
It is about choosing where the resource is really coordinated.
Quick summary
What to keep in your head
- Resource concurrency needs one clear coordination point, not locks scattered across random helpers.
- Not every conflict needs a lock. Sometimes per-key serialization, optimistic state, or a queue per resource works better.
- The contested resource needs to be explicit in the flow design.
- A lock without owner semantics, timeout, and recovery becomes an operational problem very quickly.
Practice checklist
Use this when you answer
- If two flows compete for the same resource, do I know where coordination actually happens?
- Am I using a lock because I really need one or because I modeled contention badly?
- If the lock gets stuck or expires, does the system know how to recover?
- Can I explain why I chose a lock, a queue by key, or optimistic control?
You finished this article
Share this page
Copy the link manually from the field below.