Help us shape the future of Go! Take the 2026 Go Developer Survey

queue

package
v0.42.0 Latest Latest
Warning

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

Go to latest
Published: Nov 3, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package queue is the engine's persistent queue.

The queue lives in Postgres, not in an in-memory channel: "never depend exclusively on an in-memory channel for critical jobs". A process that dies with items in a channel loses work; one that dies with items in a table does not.

The claim uses `FOR UPDATE SKIP LOCKED`, the standard pattern for a queue in Postgres: several dispatchers compete over the same table without blocking each other and without handing out the same item twice. The alternative -- a SELECT followed by an UPDATE -- has a race between the two statements.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Item

type Item struct {
	ID          int64
	RunID       uuid.UUID
	Priority    int
	AvailableAt time.Time

	// ClaimedAt is the claim this holder knows: reivindicado_em as the claim
	// wrote it. It is the fence on everything the holder does afterwards --
	// Renew, Done, Release -- because a reclaim always writes a new one, so the
	// pair (ID, ClaimedAt) names one claim and not merely one item.
	//
	// Zero means "no claim", which is what the sweep hands back: it leaves the
	// item unclaimed, and the orphan path's own Done and Release are fenced on
	// it staying that way.
	ClaimedAt time.Time
}

Item is one entry in the queue.

type Queue

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

Queue operates on queue_items.

func New

func New(pool *pgxpool.Pool) *Queue

func (*Queue) Claim

func (q *Queue) Claim(ctx context.Context, worker string, limite int) ([]Item, error)

Claim claims up to `limite` items for this worker.

The limit is how concurrency is enforced: the dispatcher asks only for the slots it has free. There is no path in which more items leave the queue than concurrency allows, because whoever counts the slots is whoever asks.

Claims are serialized across processes by an advisory lock (see claimLock).

func (*Queue) Done

func (q *Queue) Done(ctx context.Context, it Item) error

Done removes the item: the work finished and does not come back.

Fenced on the claim (#121). A holder whose claim the sweep took and somebody else claimed again would otherwise delete the item that other attempt is running -- and the queue would forget a run still in flight.

func (*Queue) Enqueue

func (q *Queue) Enqueue(ctx context.Context, runID uuid.UUID, priority int, availableAt time.Time) error

Enqueue puts a run in the queue. `disponivelEm` zero means NOW, measured by the DATABASE's clock.

`ON CONFLICT DO NOTHING` on run_id's unique: enqueueing the same run twice is a no-op, not an error. That is the behaviour §29 asks for -- the operation tolerates repetition.

The clock difference matters: the process's clock can be a few milliseconds ahead of Postgres's, and an item written with the application's `time.Now()` stays invisible until the database catches up. Nothing is lost -- the next cycle picks it up -- but it is unexplainable latency, and it is what made a concurrency test hand out 4 items where 5 were ready.

func (*Queue) Recover

func (q *Queue) Recover(ctx context.Context, limite time.Duration) ([]Item, error)

Recuperar returns to the queue the items whose holder has been silent longer than `limite`: no renewal for that long, or none at all and a claim that old. Measuring the claim alone took runs from live holders (#121).

The items come back with no claim (a zero ClaimedAt), because that is what this leaves behind.

It is the safety net against a dead worker: without it, an item claimed by a process that crashed would stay stuck forever. That was exactly the failure mode of the zombie runs that jammed pipelines for 33 days in the previous system.

func (*Queue) Release

func (q *Queue) Release(ctx context.Context, it Item, atraso time.Duration) error

Release returns the item to the queue, available after `atraso`.

Used on retry and when a dispatcher is interrupted before finishing: the item becomes free again instead of staying stuck on a worker that died.

Fenced on the claim, as Done is, so a stale holder cannot hand somebody else's run back to the queue.

func (*Queue) Renew

func (q *Queue) Renew(ctx context.Context, it Item) (held bool, err error)

Renew says the claim is still held. It is fenced on the claim itself, not on the item: a reclaim writes a new reivindicado_em, so a stale holder's renewal matches nothing -- and nothing is the answer that tells it it lost.

`held` false with no error is that answer. An error is the database not answering, which says nothing about the claim either way.

func (*Queue) Size

func (q *Queue) Size(ctx context.Context) (pending, claimed int, err error)

Size counts pending and claimed items, for observability.

Jump to

Keyboard shortcuts

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