QueuePushStrategy Options in ApraPipes: Blocking vs Non-Blocking Frame Delivery
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 (lines 12-16), where the QuePushStrategy::QuePushStrategyType enum declares the three available options. The factory method QuePushStrategy::getStrategy in 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 (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.
// 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 (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.
// 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.
// 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 creates the appropriate implementation based on the enum value and module ID.
As shown in 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
quePushStrategyTypeand instantiated throughQuePushStrategy::getStrategyinbase/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 (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. You must set quePushStrategyType before the strategy object is instantiated, typically in the module's constructor or initialization list.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →