Queue Buffer
A bounded production line where a producer generates items faster than a consumer can process them, demonstrating the Queue primitive with drop-on-overflow.
What it demonstrates
- Queue primitive with
maxCapacityandoverflowPolicy: 'drop' - Producer-consumer pattern with mismatched rates
- Auto-collected statistics for throughput and drop analysis
Scenario
- Producer: generates items with exponential inter-arrival time (mean = 1.0)
- Consumer: processes items with exponential service time (mean = 1.2, slightly slower)
- Buffer: capacity of 5 items, drop policy on overflow
Because the consumer is slower than the producer, the buffer will frequently fill up and items will be dropped.
Code
import { SimulationEngine, Queue } from 'simloop';
type Events = {
'item:produce': { itemId: number };
'item:consume': Record<string, never>;
};
const sim = new SimulationEngine<Events>({
seed: 42,
maxTime: 500,
logLevel: 'silent',
});
const buffer = new Queue<number>('buffer', { maxCapacity: 5, overflowPolicy: 'drop' });
sim.on('item:produce', (event, ctx) => {
buffer.enqueue(ctx, event.payload.itemId);
// Schedule next production (mean inter-arrival = 1.0)
ctx.schedule('item:produce', ctx.clock + ctx.dist.exponential(1.0)(), {
itemId: event.payload.itemId + 1,
});
});
sim.on('item:consume', (_e, ctx) => {
const item = buffer.dequeue(ctx);
if (item !== undefined) {
ctx.stats.increment('consumed');
}
// Schedule next consumption (mean inter-service = 1.2)
ctx.schedule('item:consume', ctx.clock + ctx.dist.exponential(1 / 1.2)(), {});
});
sim.init((ctx) => {
ctx.schedule('item:produce', 0, { itemId: 1 });
ctx.schedule('item:consume', 0.5, {});
});
const result = sim.run();
const enqueued = result.stats['queue.buffer.enqueued']?.count ?? 0;
const dequeued = result.stats['queue.buffer.dequeued']?.count ?? 0;
const dropped = result.stats['queue.buffer.dropped']?.count ?? 0;
const waitTime = result.stats['queue.buffer.waitTime'];
console.log(`Sim time: ${result.finalClock.toFixed(1)}`);
console.log(`Produced: ${enqueued + dropped}`);
console.log(`Enqueued: ${enqueued}`);
console.log(`Consumed: ${dequeued}`);
console.log(`Dropped: ${dropped}`);
console.log(`Drop rate: ${(dropped / (enqueued + dropped) * 100).toFixed(1)}%`);
console.log(`Avg wait: ${waitTime?.mean.toFixed(2) ?? 'N/A'}`);
console.log(`Max wait: ${waitTime?.max.toFixed(2) ?? 'N/A'}`);
console.log(`Wall clock: ${result.wallClockMs.toFixed(1)} ms`);Key takeaways
- With
overflowPolicy: 'drop', items are silently discarded when the buffer is full — no error thrown - Queue auto-collects
enqueued,dequeued,dropped,waitTime, andqueueLengthstatistics - The drop rate is a natural consequence of the producer being faster than the consumer
- Switch to
overflowPolicy: 'block'if the producer should be held until space frees up (backpressure)
Last updated on