Concurrent blocking FIFO queue backed by RingBuffer[T].
producer goroutines ──Enqueue/ForceEnqueue──▶ [ queue ] ──Pop──▶ consumer goroutine
- Producers never block.
Enqueuerejects when full;ForceEnqueueevicts the oldest item. - The consumer blocks.
Popsleeps until an item is available, the context is canceled, or the queue is closed. - Designed for N producers, 1 consumer. Multiple concurrent consumers are not a supported pattern.
q := carousel.NewRingQueue[string](3)
defer q.Close()
_ = q.Enqueue("alpha")
_ = q.Enqueue("beta")
item, _ := q.Pop(context.Background())
fmt.Println(item)
fmt.Println(q.Drain())NewRingQueue[T](capacity int) *RingQueue[T]
Allocates a new queue of the given capacity. Panics if capacity < 1.
Enqueue(item T) error
Appends item to the back of the queue. Non-blocking.
| Error | Condition |
|---|---|
ErrFull |
Queue is at capacity — item is not added |
ErrClosed |
Queue has been closed |
ForceEnqueue(item T) (evicted bool, err error)
Appends item to the back. If the queue is full, the oldest item is silently evicted. Returns evicted=true when an eviction occurred. Only returns ErrClosed — never ErrFull.
Pop(ctx context.Context) (T, error)
Removes and returns the front item. Blocks if the queue is empty.
| Return | Condition |
|---|---|
item, nil |
Item successfully dequeued |
zero, ctx.Err() |
Context was canceled or deadline exceeded |
zero, ErrClosed |
Queue was closed and no items remain |
Items already in the queue when
Closeor context cancellation occurs are still delivered.ErrClosedandctx.Err()are only returned after the buffer is drained.
ctx must be non-nil. Pass context.Background() to block indefinitely until an item is available or the queue is closed.
Close()
Closes the queue. Safe to call multiple times. After Close:
EnqueueandForceEnqueuereturnErrClosedimmediately.- Pending and future
Popcalls drain remaining items, then returnErrClosed.
Len() int
Number of items currently in the queue.
Cap() int
Maximum number of items the queue can hold. Fixed at construction time.
Drain() []T
Removes and returns all current items in FIFO order without blocking. Returns nil if the queue is empty. Useful for flushing remaining items after Close.
Snapshot() []T
Returns a copy of all current items in FIFO order without removing them. Returns nil if the queue is empty. Non-destructive: queue state is unchanged. Holds the queue mutex for the duration of the in-package copy (no user code runs under the lock); lock hold time is O(N) where N = Len() at the moment of the call. Independence of the returned slice is shallow — see RingBuffer.Snapshot for details.
Run make bench-sync to refresh these local numbers.
Measured on darwin/arm64 (Apple M1 Max).
| Operation | ns/op | B/op | allocs/op |
|---|---|---|---|
ForceEnqueue (serial, no contention) |
13.91 | 0 | 0 |
ProducerConsumer (1 producer + 1 consumer) |
67.29 | 0 | 0 |
ForceEnqueue (parallel writers) |
109.4 | 0 | 0 |
Snapshot (256 items) |
680.9 | 6,528 | 1 |
The serial baseline (~14 ns) reflects uncontended mutex overhead on top of the underlying RingBuffer (~3 ns). The producer/consumer benchmark still reports 0 allocs/op, but may show a few B/op from the benchmark harness.