Skip to content

Waiting strategies

Pass a publisher strategy type and a consumer strategy type to EventBus. Each must expose pub fn wait() void: a static, zero-argument function with no receiver or error return. The bus does not create or pass a strategy instance. It validates the strategy when forming the bus type.

waiting_strategy.BusySpin is the built-in strategy. Its wait() returns immediately. Loops using it repeatedly poll, potentially occupying a CPU core. Choose behavior according to your latency, CPU, and scheduling needs; there is no universal fastest strategy.

Terminal window
zig build example-waiting_strategy
const std = @import("std");
const zigrupt = @import("zigrupt");
const Yield = struct {
// A static zero-argument function, with no self pointer or error return.
pub fn wait() void {
std.Thread.yield() catch {};
}
};
comptime {
zigrupt.waiting_strategy.validateWaitingStrategy(Yield);
}
var count: usize = 0;
fn handle(events: []const usize) usize {
count += events.len;
return events.len;
}
const Bus = zigrupt.EventBus(usize, false, &.{handle}, Yield, Yield);
pub fn main() !void {
var bus = try Bus.init(std.heap.page_allocator, 8, 4);
defer bus.deinit();
try bus.start();
errdefer bus.stop() catch {};
for (0..100) |value| try bus.produce(value);
try bus.stop();
if (count != 100) return error.MissingEvents;
std.debug.print("waiting_strategy: 100 events delivered using Yield\n", .{});
}

Yielding asks the scheduler to let another thread run, but does not guarantee a switch or a particular delay. Compare under representative workloads.

The publisher strategy runs while a claimed slot cannot yet be reused. The consumer strategy runs while startup is finishing and while a running consumer is waiting for its next publication. It is not a callback after every batch, and returning zero from a handler does not invoke it. The drain loop does not use it to wait for missing publications, which is another reason producers must complete before stop().

A strategy can be called concurrently by multiple producers or consumers. Any shared mutable strategy state requires synchronization; state specific to a thread can use appropriate thread-local storage. Strategies must eventually return so the bus can recheck progress. The current interface supplies no notification/wakeup registration, so indefinite parking requires coordination outside this API and can prevent progress.