Queues look harmless on architecture diagrams.

A service publishes a message. A queue sits in the middle. Another service consumes it. The arrows are clean, the systems are decoupled, and the design appears more resilient than the synchronous version it replaced.

Often it is.

But the little queue-shaped box hides one of the most important facts about distributed systems: work that has been accepted but not completed has not disappeared. It is waiting.

And waiting has a cost.

It may be a customer waiting for an order confirmation, a payment waiting to settle, a document waiting to be indexed, an event waiting to update a downstream system, or a security finding waiting to be evaluated. A backlog is not simply infrastructure telemetry. It is unfinished business.

This is why I think queue depth deserves to be treated as more than an operational metric.

In many systems, queue depth is a business metric expressed in technical units.

Asynchrony Does Not Remove Latency

One of the reasons asynchronous architecture is so useful is that it separates acceptance from processing.

A user action does not have to wait while every downstream activity finishes. A producer can continue even when a consumer is temporarily unavailable. Traffic spikes can be buffered instead of immediately overwhelming a slower dependency.

Microsoft's current Azure Architecture Center guidance describes queue-based load leveling in exactly these terms: a queue can absorb intermittent heavy loads, allow a service to process work at its own pace, improve availability, and reduce the need to provision every consumer for peak demand.

Those are substantial advantages.

But asynchronous processing does not eliminate latency. It relocates it.

In a synchronous design, latency is visible to the caller. In an asynchronous design, some of that latency becomes queue age.

That difference is easy to miss because the API may still return in 80 milliseconds. The frontend looks fast. The producer's availability dashboard is green.

Meanwhile, the work requested by the customer may be fifteen minutes behind.

A fast acknowledgement and a fast outcome are not the same thing.

A Queue Is a Collection of Promises

I find it useful to think of every queued message as a promise the system has made.

"I accepted your payment instruction."

"I received your upload."

"I will send this notification."

"I will synchronize this account."

Once the system acknowledges the request, the responsibility has moved from the user to us.

That changes how we should think about backlog.

Ten thousand messages in a queue are not merely ten thousand records in a broker. They may represent ten thousand customers whose expectations are now attached to the organization's ability to drain that queue correctly and quickly.

The business meaning depends on the workload. A queue containing image-thumbnail jobs can tolerate a very different backlog from one containing fraud decisions or trade instructions.

That is why a universal alarm such as "queue depth greater than 10,000" is rarely enough.

The better question is: How old can this work become before the business outcome is no longer acceptable?

Depth Without Time Can Mislead You

Queue depth is useful, but by itself it can be deceptive.

A queue of 50,000 messages might be healthy if consumers process 20,000 messages per second. A queue of 500 might be a serious incident if each message takes thirty seconds to process and the business expects completion within two minutes.

AWS makes a related point in its guidance for scaling ECS workers from SQS: raw queue depth does not scale proportionally with the number of consumers, so AWS recommends reasoning about backlog per worker and acceptable message latency rather than simply reacting to the total count.

This is the architectural shift I care about.

Do not begin with infrastructure capacity. Begin with the time promise.

If a workflow should normally finish within five minutes, then five minutes is not just an application requirement. It becomes an input into consumer concurrency, autoscaling policy, retry behavior, partitioning, dead-letter handling, downstream capacity, and operational alerts.

Latency budgets should travel through the architecture.

Backlogs Change the Shape of Failure

Queues are excellent at preventing a temporary downstream failure from immediately becoming an upstream failure.

That does not mean the failure is gone.

It may be accumulating.

Imagine a consumer normally handles 1,000 messages per second and producers generate roughly the same amount. The consumer becomes unavailable for one hour. When it returns, it does not merely need enough capacity to handle the current 1,000 messages per second. It needs spare capacity above the arrival rate to remove the accumulated backlog.

If production and consumption return to exactly the same rate, the queue never catches up.

This sounds obvious when written down. It is surprisingly easy to overlook in capacity planning.

Recovery capacity is different from steady-state capacity.

A system designed to run comfortably at normal load can still have an unacceptable recovery time after an outage because there is no headroom to drain deferred work.

AWS's current resilience guidance makes the broader point that overload itself is a source of failure and that systems need deliberate mechanisms such as quotas, throttling and load shedding to avoid turning excess demand into widespread unavailability.

Queues buy time. Architecture still has to decide what to do with that time.

Retries Can Turn Waiting Into Amplification

Retries are another place where a reasonable local decision can create a system-level problem.

A consumer fails to process a message, so it retries. Sensible.

But if the underlying dependency is degraded, thousands of consumers may retry simultaneously. The original workload is now accompanied by retry workload. If retries happen at multiple layers, one business request can become several technical requests precisely when the downstream system has the least capacity to handle them.

Then the queue grows faster, messages become older, timeouts trigger more retries, and the recovery path becomes harder than the original failure.

This is why idempotency, bounded retries, exponential backoff, jitter, dead-letter handling and poison-message isolation are not implementation trivia.

They determine the failure dynamics of the architecture.

A recent AWS Architecture Blog article on testing SQS resilience makes a useful distinction: a dead-letter queue is a safety net for messages that cannot be processed successfully, not an overflow buffer for normal capacity problems. It also emphasizes that consumers must tolerate redelivery.

The point is larger than SQS.

Every asynchronous system needs an explicit answer to this question: What happens to work that cannot make forward progress?

Not All Work Deserves the Same Place in Line

FIFO sounds fair until the oldest work blocks the most important work.

Many systems eventually discover that a single undifferentiated queue is carrying several kinds of business promises with very different urgency.

A password-reset email and a weekly marketing digest are both email. Operationally, they are not the same workload.

A real-time account update and a nightly enrichment job may touch the same downstream service. They should not necessarily compete for the same recovery capacity.

This is where architecture has to introduce intentional prioritization: separate queues, workload classes, reserved capacity, fair scheduling, rate limits, or explicit degradation policies.

Prioritization is sometimes uncomfortable because it forces a business decision that a generic queue conveniently avoided.

Which work matters most when capacity is scarce?

That question already has an answer in production. If we do not design one, the answer will be determined accidentally by arrival order, partition assignment, retry timing, or whichever customer generates the most traffic.

Autoscaling Is Not a Substitute for Throughput Design

Cloud platforms make it tempting to treat backlog as an autoscaling problem.

Queue gets deeper; add workers.

Sometimes that is exactly right.

But consumers rarely operate in isolation. More workers may create more database connections, more API calls, more lock contention, more writes to a shared partition, or more pressure on a third-party service.

Scaling the consumer can simply move the bottleneck one hop downstream.

Good throughput design therefore asks about the entire path: producer rate, queue behavior, consumer rate, downstream limits, partition strategy, concurrency, batch size, retry traffic and recovery headroom.

This is one reason distributed systems can behave counterintuitively. Each component may be capable of scaling independently while the end-to-end workflow cannot.

The architecture is constrained by the narrowest sustainable part of the path.

The Same Queue Exists in Engineering Organizations

There is an organizational version of this pattern too.

Architecture reviews waiting for approval. Pull requests waiting for reviewers. Security exceptions waiting for assessment. Environments waiting to be provisioned. Teams waiting on another team before they can release.

These are queues even when there is no message broker involved.

DORA's research consistently emphasizes fast flow, working in small batches, continuous integration, streamlined approvals, loosely coupled teams and fast feedback. Its current software-delivery metrics separate throughput from instability, including deployment rework rate as a measure of unplanned corrective work.

Team Topologies makes a related argument from organizational design: blocking dependencies and repeated handoffs slow the flow of value, while self-service capabilities can remove coordination from routine interactions.

The parallel is useful because software architects sometimes optimize machine queues while accepting human queues as unavoidable process.

Both consume lead time.

Both hide work in progress.

Both become dangerous when arrival rate persistently exceeds service rate.

And both often improve when we remove unnecessary work rather than simply adding more capacity.

Measure the Age of the Promise

If I were reviewing an asynchronous architecture, I would want more than a box labeled Kafka, SQS, Service Bus or RabbitMQ.

I would ask:

  • What business promise does each message represent?
  • What is the acceptable end-to-end completion time?
  • Do we measure the age of the oldest useful work, not just queue depth?
  • What sustained arrival rate can the complete downstream path handle?
  • How much recovery headroom exists after a one-hour consumer outage?
  • Which workloads receive priority when capacity is constrained?
  • What happens when a message repeatedly fails?
  • Can consumers safely process duplicates?
  • Can scaling consumers overwhelm the next dependency?
  • At what point should the system reject, defer or shed new work instead of accepting another promise it cannot keep?

Those questions turn messaging from a technology choice into an architecture conversation.

Architecture Is Also the Management of Time

We tend to describe architecture spatially.

Services, boundaries, regions, networks, databases, layers.

But distributed systems also have a temporal architecture.

Work arrives. Work waits. Work expires. Work retries. Work overtakes other work. Work accumulates during failure and has to be paid back during recovery.

A queue is where that temporal dimension becomes visible.

Used well, queues give systems room to breathe. They absorb bursts, isolate failures, enable independent scaling, and let us trade immediate completion for resilience and efficiency.

Used carelessly, they allow a system to look healthy while obligations quietly accumulate behind the interface.

So I would not ask only whether a queue is available, durable, encrypted, replicated, or deep enough.

I would ask whether the organization understands what is waiting inside it.

Because a backlog is not just stored work. It is stored time—and usually, someone is waiting on the other side of it.

Further Reading

DORA. Software Delivery Performance Metrics and Value Stream Management guidance, 2026.

Microsoft Azure Architecture Center. Queue-Based Load Leveling Pattern, updated June 12, 2026.

AWS. Availability and Beyond: Understanding and Improving the Resilience of Distributed Systems on AWS, 2026.

AWS Architecture Blog. Testing Application Resilience with Amazon SQS and AWS Fault Injection Service, September 2026.

Team Topologies. Organizing for Fast Flow of Value, 2026.