Queues should be empty

I’ve been writing a pubsub listener for work recently and had this silly “shower thought”: the ideal queue should be empty. Why? If the queue is not empty, it means that whatever job is consuming from the queue is not keeping up with messages coming into it. Ok, then if queues are supposed to be empty, then what are they good for?

Spikey workloads

One use for a queue is handling “spikey” workloads or scenarios where there is a mismatch between the rate at which events are produced and the rate at which they can be consumed. For instance, if there’s a sudden surge in demand for a service or product, a queue can help absorb the influx of requests until the system can scale up to handle the increased load.

Safely persisting data

Another use for a queue is safely persisting data. In pubsub, for example, a message is left on the queue until it’s been processed or acknowledged (ACK’d). If the process fails, it will never have been ACK’d so it will stay safely on the queue until the job is restarted.

A job can also be failed purposefully with a negative acknowledgement (a NACK). You might do this if the job is not ready yet or if a service the job depends on has failed. After a NACK, the message will be returned to the queue to be processed at a later time. Usually using a backoff policy so that the consumer doesn’t continuously pull the same item.

Decoupling components

Queues can be used to decouple components in a distributed system. If one component produces events and another component consumes them, a queue can act as a buffer between the two components. This way, the producer doesn’t need to know anything about the consumer and vice versa. They simply interact with the queue, which handles the communication between them.

Enabling asynchronous processing

Another use for queues is to enable asynchronous and/or parallel processing. With a queue, you can submit a job or task to be executed later and avoid blocking the caller. If you have an application that generates PDFs, you could submit the task and ACK immediately allowing the job to finish in the background. It also makes it easy to parallelize jobs by having multiple consumers pull from the same queue.

Empty queues may be the best queues…

… but they’re still useful.