Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →When an Elixir producer sends messages faster than a consumer can process them, the consumer’s mailbox can grow into a backlog. The solution is to make flow control explicit: wait for acknowledgements, let consumers request bounded demand, or choose a deliberate overload policy when the upstream source cannot be slowed.
One illustrative scenario is a publisher emitting 10,000 messages per second while an email notifier can send 50 per second. Those figures frame the problem; they are not industry measurements. The important question is what happens to work the consumer cannot yet handle.
As an Amazon Associate I earn from qualifying purchases.
Why asynchronous messaging can create a backlog
In the example discussed by krishnadaspc in Part 9 of Building Distributed Systems in Elixir, send/2 is asynchronous from the sender’s perspective: sending a message does not mean the recipient has finished processing it. If messages arrive faster than the recipient handles them, queued work accumulates.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minuteThis is not necessarily a problem for every short burst. It becomes a capacity problem when the producer remains faster over time, or when a burst creates more queued work than the process can safely retain. A growing mailbox can increase memory use and delay useful work behind older messages.
#1 Best Overall
Three ways to control the flow
| Approach | How flow is controlled | Backlog and trade-off | When it fits |
|---|---|---|---|
| Uncoordinated push | The producer sends without waiting for consumer progress. | No acknowledgement round trip, but a slow consumer can accumulate queued messages. | Fire-and-forget work only when backlog and loss risks are handled elsewhere. |
| Stop-and-wait | The producer sends one item and waits for an acknowledgement associated with that item’s reference. | In the simple pattern, roughly one item is outstanding at a time. Work is serialized, and each acknowledgement’s latency affects progress. | Low-volume exchanges or interactions that are naturally synchronous. |
| Demand window | The consumer requests a quantity of work; the producer emits against that available demand. | Limits outstanding demand to the window while allowing work to be pipelined. Other buffers can still accumulate work. | Streams where consumers can report capacity and a bounded amount of in-flight work is useful. |
Uncoordinated push
A sender can dispatch quickly because it does not wait for the recipient to complete each message. That is useful when the work is intentionally fire-and-forget, but it provides no feedback that the consumer is keeping up. If delivery must be complete, or if queued work must remain bounded, those guarantees need to come from another part of the design.
Stop-and-wait acknowledgements
Stop-and-wait adds a feedback loop: send an item, then continue only after receiving an acknowledgement tied to that item’s reference. It is straightforward and limits outstanding work in the basic example. Its cost is serialization: the sender cannot use the next item to keep the consumer busy while waiting for the current acknowledgement.
Demand windows
With demand-driven flow control, a consumer signals how many events it is ready to receive. GenStage documents that producers emit no more events than consumers have requested. A bounded demand window therefore controls one part of the flow while still allowing several items to be in flight.
Demand is not a universal cap on every queue in an application. A producer’s internal buffer, an external source’s buffer, or another stage can still hold work. Each buffer needs a limit or a clearly defined overload policy.
Rank #3
Using GenStage and Broadway in an Elixir pipeline
GenStage stages can be producers, consumers, or both. Consumers send demand upstream, and producers emit within that demand. The GenStage documentation recommends stages when backpressure or routing is needed, rather than adding stages merely to create concurrency. Check the documentation for the version your application uses before relying on specific APIs or defaults.
Broadway is a concurrent, multi-stage processing library built on GenStage. Its documented capabilities include backpressure, batching, acknowledgements, fault tolerance, graceful shutdown, rate-limiting, and metrics. Its architecture uses producer, processor, and batcher stages. Those features provide pipeline building blocks; they do not remove the need to decide what should happen when demand, buffers, or downstream capacity are exhausted.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.What to do when the upstream source cannot be throttled
If an external source keeps producing regardless of downstream capacity, the application has to define what happens to excess work. The right policy depends on whether completeness, freshness, or explicit feedback to the caller matters most.
- Drop newest: Keep older queued work and discard arrivals that cannot be accepted. This may suit workloads where already-accepted items matter more than the latest state, but it loses new data.
- Drop oldest: Discard older queued work to make room for fresher arrivals. This can suit workloads where the latest state is more useful than stale updates, but it sacrifices completeness.
- Reject at the boundary: Refuse work before it enters the overloaded part of the system, such as by rejecting an HTTP request. This gives a caller a visible failure where the boundary supports it, but rejecting one request does not necessarily regulate every external source.
Choose and document the behavior in terms of the application’s delivery promise. If every item must be processed, silently dropping data is incompatible with that promise; use a design that can preserve work or report failure. If freshness matters more than a complete history, dropping stale queued updates may be an intentional trade-off.
Best Value
Inspecting a queue without mistaking a snapshot for a benchmark
Elixir’s Process.info/2 can be used to inspect process information such as a queue and memory during a demonstration. The values shown in the source article are outputs from that particular experiment, not general performance guarantees or a benchmark for other systems. Queue and memory readings describe a moment; they do not, by themselves, establish how a production workload will behave over time.
The article also mentions Erlang socket active modes, but configuration advice depends on the relevant Erlang/OTP behavior and version. Consult the official documentation for the runtime and socket API in use before applying that example.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →




