Skip to Content

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 maxCapacity and overflowPolicy: '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, and queueLength statistics
  • 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