queue

package
v0.0.1-dev.137 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 11, 2026 License: MIT Imports: 4 Imported by: 0

Documentation

Overview

Package queue provides a coalescing, rate-limited, per-key work queue with the same semantics as Kubernetes client-go's workqueue: a key added while pending is deduplicated, a key added while being processed is re-delivered exactly once after the current run finishes, and no two workers ever process the same key concurrently. This is the serialization backbone of the orchestrator's single-writer reconcile model (RFC #129 Phase 3): correctness against concurrent spec writers comes from the store's UpdateFunc CAS, while this queue guarantees reconciles of one service never interleave.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Queue

type Queue struct {
	// contains filtered or unexported fields
}

Queue is a coalescing per-key work queue. All methods are safe for concurrent use.

Key lifecycle (client-go workqueue semantics):

Add(k)      : k ∉ dirty → dirty + pending(order); k ∈ dirty → no-op (coalesced);
              k ∈ processing → dirty only (re-delivered after Done)
Get()       : pops the oldest pending key → processing (removed from dirty)
Done(k)     : k leaves processing; if re-Added meanwhile (k ∈ dirty) → pending again

func New

func New(name string, rl RateLimiter) *Queue

New creates a Queue. name is used for identification in logs/stats only. A nil rl gets the DefaultRateLimiter.

func (*Queue) Add

func (q *Queue) Add(key string)

Add marks key as needing a run. Duplicate adds of a pending key coalesce; adding a key that is currently being processed schedules exactly one re-run after the in-flight run completes. Add on a shut-down queue is a no-op.

func (*Queue) AddAfter

func (q *Queue) AddAfter(key string, d time.Duration)

AddAfter adds key after delay d (immediately when d <= 0). Implemented with one timer per call rather than a shared heap: Add's dirty-set dedup makes redundant timers harmless, and at orchestrator scale (tens of services) the simplicity wins. A timer firing after ShutDown lands on the no-op Add path.

func (*Queue) AddRateLimited

func (q *Queue) AddRateLimited(key string)

AddRateLimited adds key after the rate limiter's backoff for it.

func (*Queue) Done

func (q *Queue) Done(key string)

Done releases key after processing. If the key was re-Added while being processed, it is requeued for exactly one further run.

func (*Queue) Forget

func (q *Queue) Forget(key string)

Forget clears key's backoff history. Call after a successful sync.

func (*Queue) Get

func (q *Queue) Get() (key string, shutdown bool)

Get blocks until a key is available or the queue shuts down. The returned key is exclusively held by the caller (no other Get returns it) until the caller invokes Done.

func (*Queue) Len

func (q *Queue) Len() int

Len returns the number of pending (not in-flight) keys.

func (*Queue) ShutDown

func (q *Queue) ShutDown()

ShutDown stops the queue: pending keys already in the queue are still delivered, then Get returns shutdown=true to every waiter. Idempotent.

func (*Queue) Stats

func (q *Queue) Stats() Stats

Stats returns a snapshot of the queue counters.

func (*Queue) Work

func (q *Queue) Work(ctx context.Context, n int, handler func(ctx context.Context, key string) error)

Work runs n workers calling handler for each key until ctx is cancelled or the queue is shut down, then blocks until all workers have exited. A handler error requeues the key with backoff; success resets its backoff. Per-key exclusivity is inherited from Get/Done: handler never runs concurrently for the same key.

type RateLimiter

type RateLimiter interface {
	// When returns the delay to apply before re-adding key, growing with each
	// consecutive call for the same key.
	When(key string) time.Duration
	// Forget resets key's failure history (called after a successful sync).
	Forget(key string)
	// NumRequeues reports how many times key has been rate-limited since the
	// last Forget.
	NumRequeues(key string) int
}

RateLimiter computes per-item retry delays for AddRateLimited. Implementations must be safe for concurrent use.

func DefaultRateLimiter

func DefaultRateLimiter() RateLimiter

DefaultRateLimiter matches the client-go default: 5ms base doubling up to 1000s. The reconciler's periodic resync is the safety net for anything that backs off this far.

func NewItemExponentialRateLimiter

func NewItemExponentialRateLimiter(base, max time.Duration) RateLimiter

NewItemExponentialRateLimiter returns a per-key exponential-backoff limiter.

type Stats

type Stats struct {
	Adds              uint64        // Add calls that enqueued or dirtied a key
	Coalesced         uint64        // Add calls absorbed by an already-dirty key
	Requeues          uint64        // AddRateLimited calls (failed syncs)
	Processed         uint64        // handler invocations completed (via Work)
	Depth             int           // current pending keys
	MaxDepth          int           // high-water mark of Depth
	WorkDurationTotal time.Duration // cumulative handler runtime (via Work)
}

Stats is a point-in-time snapshot of queue counters, for observability.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL