Skip to main content

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

Andrews Ribeiro

Founder & Engineer

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

Practice checklist

Use this when you answer

Next article Anti-Corruption Between Internal Domains Without Becoming an Ornamental Layer Previous article Blast-Shield Layers for Internal Spikes Without Taking Down the Core

Keep exploring

Related articles