# QueuePushStrategy Options in ApraPipes: Blocking vs Non-Blocking Frame Delivery

> Explore ApraPipes QueuePushStrategy options BLOCKING, NON_BLOCKING_ANY, and NON_BLOCKING_ALL_OR_NONE. Learn how to optimize frame delivery for your pipeline modules.

- Repository: [Apra Labs/aprapipes](https://github.com/apra-labs/aprapipes)
- Tags: deep-dive
- Published: 2026-02-25

---

**ApraPipes provides three QueuePushStrategy options—BLOCKING, NON_BLOCKING_ANY, and NON_BLOCKING_ALL_OR_NONE—that control how frames flow between pipeline modules, balancing guaranteed delivery against throughput performance.**

The `apra-labs/aprapipes` repository implements a modular media processing framework where **QueuePushStrategy options in ApraPipes** determine the back-pressure behavior between source and destination modules. These strategies define whether frames wait for queue space, drop individually when queues are full, or deliver atomically to multiple consumers.

## Understanding QueuePushStrategy in ApraPipes

The strategy pattern is defined in [`base/include/QuePushStrategy.h`](https://github.com/apra-labs/aprapipes/blob/main/base/include/QuePushStrategy.h) (lines 12-16), where the `QuePushStrategy::QuePushStrategyType` enum declares the three available options. The factory method `QuePushStrategy::getStrategy` in [`base/src/QuePushStrategy.cpp`](https://github.com/apra-labs/aprapipes/blob/main/base/src/QuePushStrategy.cpp) (lines 5-15) instantiates the appropriate implementation class based on the selected enum value.

## The Three QueuePushStrategy Options

### BLOCKING: Guaranteed Delivery with Back-Pressure

The **BLOCKING** strategy, implemented by the base `QuePushStrategy` class, provides synchronous frame delivery. When a module calls `push`, the frame container is forwarded directly to the target queue via `mQueByModule[dstModuleId]->push(frames)`. If the downstream queue is full, the call blocks until space becomes available.

This approach guarantees zero frame drops but introduces **back-pressure**—the producer stalls when consumers cannot keep up. According to the source code in [`base/include/Module.h`](https://github.com/apra-labs/aprapipes/blob/main/base/include/Module.h) (lines 46-88), this is the default strategy assigned to most modules during construction.

Use this strategy when processing video streams where every frame must be preserved, such as archival recording or frame-accurate analysis pipelines.

```cpp
// Default blocking behavior - no configuration needed
MyModule myMod("sourceId");
// myMod.quePushStrategyType == QuePushStrategy::BLOCKING

```

### NON_BLOCKING_ANY: Drop Frames to Maintain Throughput

The **NON_BLOCKING_ANY** strategy, implemented by `NonBlockingAnyPushStrategy`, uses `try_push` instead of blocking `push` calls. If the destination queue is full, the frame is immediately discarded and an internal drop counter (`mDropCount`) is incremented. The producer continues at full speed without stalling.

This strategy is explicitly selected in [`base/include/ExternalSourceModule.h`](https://github.com/apra-labs/aprapipes/blob/main/base/include/ExternalSourceModule.h) (line 13) for external capture sources. It is ideal for **live-capture scenarios** such as camera inputs or network streams where maintaining real-time throughput is more important than preserving every single frame.

```cpp
// Configure for non-blocking frame dropping
myMod.quePushStrategyType = QuePushStrategy::NON_BLOCKING_ANY;
myMod.mQuePushStrategy = QuePushStrategy::getStrategy(
    myMod.quePushStrategyType, myMod.mId);

```

### NON_BLOCKING_ALL_OR_NONE: Atomic Batch Delivery

The **NON_BLOCKING_ALL_OR_NONE** strategy, implemented by `NonBlockingAllOrNonePushStrategy`, provides **atomic batch delivery**. Frames are first buffered in an internal map (`mFramesByModule`). When `flush` is called, the strategy checks **all** downstream queues for available space. Only if every queue can accept the frames does it push the entire batch atomically. If any single queue is full, the entire batch is discarded and queues remain unchanged.

This strategy is essential for **synchronized multi-camera setups** or tightly coupled processing stages where partial delivery would corrupt state. It ensures that either all consumers receive the frame set or none do, maintaining data consistency across parallel branches.

```cpp
// Configure for atomic all-or-none delivery
myMod.quePushStrategyType = QuePushStrategy::NON_BLOCKING_ALL_OR_NONE;
myMod.mQuePushStrategy = QuePushStrategy::getStrategy(
    myMod.quePushStrategyType, myMod.mId);

```

## How to Configure QueuePushStrategy in Your Module

Modules select their strategy during construction by setting the `quePushStrategyType` member before the strategy object is instantiated. The factory method `QuePushStrategy::getStrategy` in [`base/src/QuePushStrategy.cpp`](https://github.com/apra-labs/aprapipes/blob/main/base/src/QuePushStrategy.cpp) creates the appropriate implementation based on the enum value and module ID.

As shown in [`base/include/Module.h`](https://github.com/apra-labs/aprapipes/blob/main/base/include/Module.h) (lines 46-88), the default assignment is `BLOCKING`, but modules like `ExternalSourceModule` override this to `NON_BLOCKING_ANY` for capture scenarios.

## Choosing the Right QueuePushStrategy for Your Use Case

Select your strategy based on these criteria:

- **Use BLOCKING** when you require guaranteed frame delivery and can tolerate back-pressure stalling. Essential for recording, transcoding, or any pipeline where frame drops are unacceptable.

- **Use NON_BLOCKING_ANY** when processing live feeds where maintaining capture rate is more important than completeness. Ideal for camera inputs, RTSP streams, or preview pipelines where occasional drops are preferable to freezing.

- **Use NON_BLOCKING_ALL_OR_NONE** when delivering frames to multiple synchronized consumers. Critical for multi-camera calibration, stereo vision, or any scenario where partial delivery would cause state inconsistency.

## Summary

- ApraPipes provides three **QueuePushStrategy options**: BLOCKING, NON_BLOCKING_ANY, and NON_BLOCKING_ALL_OR_NONE.
- The **BLOCKING** strategy guarantees delivery but stalls on full queues, serving as the default for most modules.
- **NON_BLOCKING_ANY** drops individual frames when queues are full, maintaining throughput for live capture sources.
- **NON_BLOCKING_ALL_OR_NONE** provides atomic batch delivery, ensuring synchronized multi-consumer pipelines remain consistent.
- Strategies are selected via `quePushStrategyType` and instantiated through `QuePushStrategy::getStrategy` in [`base/src/QuePushStrategy.cpp`](https://github.com/apra-labs/aprapipes/blob/main/base/src/QuePushStrategy.cpp).

## Frequently Asked Questions

### What is the default QueuePushStrategy in ApraPipes?

The default strategy is **BLOCKING**, assigned during module construction as defined in [`base/include/Module.h`](https://github.com/apra-labs/aprapipes/blob/main/base/include/Module.h) (lines 46-88). This ensures that modules wait for downstream queues to accept frames rather than dropping data.

### When should I use NON_BLOCKING_ANY instead of BLOCKING?

Use **NON_BLOCKING_ANY** when processing live video feeds where maintaining real-time capture speed is more important than preserving every frame. This strategy prevents the pipeline from freezing when downstream processing cannot keep up, making it ideal for camera inputs and network streams where occasional frame drops are acceptable.

### How does NON_BLOCKING_ALL_OR_NONE handle multiple downstream modules?

The **NON_BLOCKING_ALL_OR_NONE** strategy buffers frames internally and checks all downstream queues before delivery. It only pushes the frame batch if every queue has available space. If any single queue is full, the entire batch is discarded atomically, ensuring that no consumer receives partial data. This is critical for synchronized multi-camera or stereo vision pipelines.

### Can I change the QueuePushStrategy at runtime?

No, the strategy is determined at module construction time when `QuePushStrategy::getStrategy` is called in [`base/src/QuePushStrategy.cpp`](https://github.com/apra-labs/aprapipes/blob/main/base/src/QuePushStrategy.cpp). You must set `quePushStrategyType` before the strategy object is instantiated, typically in the module's constructor or initialization list.