If you have a producer with an uneven rate of production and a consumer that cannot keep pace with the producer at its peak, use a queue.
If you have a workload that need not be addressed synchronously, use a queue.
If your customer-facing application is riddled with workloads that can be deferred, move these to a queue thus making the customer-facing application lean and mean.
Think of a queue as a shock absorber.
There are workloads that need to be processed immediately with sub-millisecond latency, and then there are ones where you have the luxury of taking the time. It is advisable not to mix these in an application. The second kind of workload can be addressed by moving it to a queue and having a consumer process them.
For example, consider a scenario where you are consuming messages and persisting them in a data store. These messages are coming in at a variable rate, and at its peak, the data store cannot handle the load. You have two options. Scale the datastore to meet the peak load or slap a queue in between to absorb the shock. Queue solves this problem in a KISS manner.
Queues enable applications to be highly available while giving enough room to maneuver. As long as the queue is highly available, the chance of message loss is almost nil. Since a queue is durable, you need not perfect your consumer’s high availability; you get leeway to manage.
With applications embracing microservices paradigm, there is a lot of API back and forth. Not all API consumption has to be in real-time. Whatever can be deferred should use a queue as the transport mechanism.
Queue introduces a bit more complexity into an application but the advantage it brings to the table makes it a worthwhile investment.