Free tools Windows power users keep installed
One-click scans. No signup required.
iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
When an Elixir producer sends work faster than a consumer can finish it, asynchronous messages can pile up in the consumer’s mailbox. Backpressure prevents that mismatch from becoming unbounded work: the producer either waits for acknowledgements or emits only as much work as the consumer has requested. If the upstream source cannot be slowed, the system needs an explicit overload policy.
For example, krishnadaspc’s September 22, 2026 article frames the problem with a hypothetical publisher emitting 10,000 messages per second while an email notifier can send 50 per second. Those rates illustrate the mismatch; they are not general performance measurements. Read the article.
Why asynchronous sends can overwhelm a consumer
A call to send/2 delivers a message without waiting for the recipient process to finish handling it. That makes sending convenient and decoupled, but it does not coordinate the producer’s pace with the consumer’s capacity. If messages arrive faster than the consumer processes them for long enough, its mailbox can grow, using memory and leaving work waiting longer.
The important distinction is between sending a message and completing the work represented by that message. A producer that has successfully sent an item does not thereby know that the consumer has processed it. Without feedback or a separate queue limit, asynchronous delivery alone provides no flow control.
Three ways to control work in flight
| Approach | How flow is controlled | Backlog and trade-offs | When it can fit |
|---|---|---|---|
| Uncoordinated push | The producer sends without waiting for consumer progress. | There is no acknowledgement round trip, but a persistently slower consumer can accumulate 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 tied to that item’s reference before sending the next. | In the simple pattern, outstanding work is limited to roughly one item. Processing is serialized, and each item’s progress depends on acknowledgement latency. | Low-volume exchanges or interactions that are naturally synchronous. |
| Demand window | The consumer requests a quantity of work; the producer emits against the available demand, and the consumer replenishes demand after processing. | A configured window limits demand-driven in-flight work and allows pipelining, but does not by itself bound every queue elsewhere in the system. | Streams where consumers can signal their capacity. |
Stop-and-wait: simple feedback, limited concurrency
In a stop-and-wait design, the producer sends an item with a reference and waits until the consumer acknowledges that reference. The acknowledgement connects progress to a particular piece of work rather than merely confirming that a message was sent. This gives the producer a direct signal to continue, but it serializes the exchange: while waiting, the producer cannot use that simple protocol to send more items.
That makes stop-and-wait easy to reason about, but the acknowledgement round trip can constrain throughput. If processing or acknowledgement takes a while, the producer remains idle even if the consumer could handle additional work concurrently.
Rank #2
Demand windows: bounded, pipelined work
With demand-driven flow control, a consumer requests capacity upstream. A producer emits no more events than consumers have requested, and the consumer can ask for more as work completes. This keeps multiple items in flight while retaining a feedback mechanism.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →GenStage formalizes this model: its stages can be producers, consumers, or both; consumers send demand upstream, and producers emit no more events than requested. See the GenStage documentation for the library’s current behavior and API details.
Rank #3
Demand is not a magical end-to-end memory limit. A system may also have producer-side queues, broker buffers, socket buffers, or external source buffers. Each needs an appropriate bound or overload policy; otherwise, work can accumulate outside the demand-controlled stage.
Choosing a production approach in Elixir
Use GenStage when stages need demand or routing
GenStage is useful when a system needs backpressure or event routing between stages. Its documentation cautions against adding stages simply to create concurrency: concurrency alone is not a reason to introduce the abstraction. Confirm API details against the version installed in your project, since documentation and examples can change across versions. GenStage documentation.
Rank #4
Use Broadway for a multi-stage processing pipeline
Broadway is a concurrent, multi-stage Elixir processing library built on GenStage. Its documentation describes producer, processor, and batcher stages, as well as backpressure, batching, acknowledgements at the end of a pipeline, fault tolerance, graceful shutdown, rate-limiting, and metrics. Those capabilities can help when the application needs a structured processing pipeline rather than a hand-built message loop. Consult the Broadway introduction and architecture documentation for details appropriate to the version in use.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problemsWhen the upstream source cannot be slowed
Backpressure works only if the upstream producer or source can respond to demand. If an external source continues sending at its own pace, the system must decide what happens when its capacity is exhausted. The right choice depends on whether the application prioritizes completeness, freshness, or clear feedback to the sender.
Best Value
- Drop newest: Discard incoming items when capacity is full. This preserves older queued work, which may suit workloads where completing already accepted items matters more than serving the latest state.
- Drop oldest: Remove older queued items to make room for newer ones. This favors freshness, but sacrifices completeness and may be unsuitable when every event must be processed.
- Reject at the boundary: Refuse new work, for example by returning an HTTP rejection, so a caller can receive explicit feedback. This is useful only when the caller can understand and act on that response; rejecting one request does not necessarily regulate every external source.
Make the policy visible in the service’s contract and operations. A drop policy is deliberate data loss, while rejection shifts responsibility to the caller. If the application promises that every accepted event will be processed, dropping items is inconsistent with that promise unless there is a separate durable recovery path.
Inspecting a mailbox is a diagnostic, not flow control
The article demonstrates using Process.info/2 to inspect a process queue and memory. Those values are snapshots from that demonstration, not benchmarks or forecasts for another system. Queue length can help reveal that a consumer is falling behind, but observing a backlog does not constrain it; the system still needs demand, acknowledgements, bounded buffering, or an explicit overload policy.
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.
Recommended Free Tools

