postgres

package module
v0.0.0-...-b0e3e36 Latest Latest
Warning

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

Go to latest
Published: Apr 13, 2026 License: Apache-2.0 Imports: 18 Imported by: 0

Documentation

Overview

Package postgres provides a Postgres-backed Store that implements the four interfaces the workflow engine and its worker need:

The Store keeps one table for runs (workflow_runs), one for step progress (workflow_step_progress), and one for activity history (workflow_activity_log). Schema migrations are applied idempotently by Store.Migrate.

All writes to workflow_runs that belong to a running execution fence on (claimed_by, attempt) so that a worker that has lost its lease cannot corrupt a newer attempt's state. Fencing failures surface as github.com/deepnoodle-ai/workflow/experimental/worker.ErrLeaseLost.

Index

Constants

View Source
const DefaultSchema = "public"

DefaultSchema is the Postgres schema used when WithSchema is not supplied. Matches the behavior of the default search_path on a fresh Postgres install.

Variables

View Source
var ErrCannotDeleteRunning = runquery.ErrCannotDeleteRunning

ErrCannotDeleteRunning is an alias for runquery.ErrCannotDeleteRunning.

View Source
var ErrRunNotFound = runquery.ErrRunNotFound

ErrRunNotFound is an alias for runquery.ErrRunNotFound so existing callers comparing against postgres.ErrRunNotFound keep working. New code should use runquery.ErrRunNotFound directly.

Functions

This section is empty.

Types

type Option

type Option func(*Store)

Option configures a Store.

func WithLogger

func WithLogger(l *slog.Logger) Option

WithLogger attaches a structured logger. Defaults to a discard logger.

func WithSchema

func WithSchema(schema string) Option

WithSchema selects the Postgres schema (namespace) that will hold the store's tables. Defaults to "public". The schema name is validated as a simple SQL identifier (letters, digits, underscore, starting with a letter or underscore) to rule out injection, and then used verbatim as a quoted identifier in every query.

Migrate will run `CREATE SCHEMA IF NOT EXISTS` on the selected schema before creating tables, so the schema does not need to exist in advance.

type Run

type Run = runquery.Run

Run aliases runquery.Run so callers can write postgres.Run during the transition. New code should use runquery.Run.

type RunCursor

type RunCursor = runquery.RunCursor

RunCursor aliases runquery.RunCursor.

type RunFilter

type RunFilter = runquery.RunFilter

RunFilter aliases runquery.RunFilter.

type Store

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

Store is a Postgres-backed implementation of the worker QueueStore and the workflow engine's persistence interfaces. Construct with New and call Migrate once on startup to ensure the schema is in place.

func New

func New(pool *pgxpool.Pool, opts ...Option) *Store

New constructs a Store bound to the given pgx pool. The pool's lifecycle is owned by the caller. Panics if pool is nil.

func (*Store) AppendEvent

func (s *Store) AppendEvent(ctx context.Context, event *worker.Event) error

AppendEvent implements worker.EventStore.

func (*Store) Balance

func (s *Store) Balance(ctx context.Context, orgID string) (int, error)

Balance implements worker.CreditStore.

func (*Store) ClaimQueued

func (s *Store) ClaimQueued(ctx context.Context, workerID string) (*worker.Claim, error)

ClaimQueued implements worker.QueueStore using SELECT ... FOR UPDATE SKIP LOCKED to atomically claim the oldest queued run.

func (*Store) CleanupEvents

func (s *Store) CleanupEvents(ctx context.Context, olderThan time.Time) (int, error)

CleanupEvents implements worker.EventStore.

func (*Store) Complete

func (s *Store) Complete(ctx context.Context, claim *worker.Claim, outcome worker.Outcome) error

Complete implements worker.QueueStore with (claimed_by, attempt) fencing.

func (*Store) CountRuns

func (s *Store) CountRuns(ctx context.Context, orgID string, filter runquery.RunFilter) (int, error)

CountRuns returns the total number of rows matching filter. The cursor field on filter is ignored: counts are over the entire filtered set, not a single page.

func (*Store) DeadLetterStale

func (s *Store) DeadLetterStale(ctx context.Context, staleBefore time.Time, maxAttempts int, excludeIDs []string) ([]worker.DeadLetteredRun, error)

DeadLetterStale implements worker.QueueStore. Returns the metadata for each dead-lettered run so the worker can refund credits inline.

func (*Store) Debit

func (s *Store) Debit(ctx context.Context, orgID, runID, workflowType string, amount int) error

Debit implements worker.CreditStore. Idempotent per (run_id, "debit").

func (*Store) DeleteRun

func (s *Store) DeleteRun(ctx context.Context, orgID, id string) error

DeleteRun removes a run row by ID. Running runs cannot be deleted; the caller must cancel or wait for the run first.

Implemented as a single DELETE ... RETURNING status so the check and the delete happen atomically. If RETURNING yields no row, we fall back to a cheap existence probe to distinguish "running" from "not found."

func (*Store) Enqueue

func (s *Store) Enqueue(ctx context.Context, run worker.NewRun) error

Enqueue implements worker.QueueStore. The insert runs in its own connection. When the insert must be atomic with writes to adjacent tables (credit ledger, idempotency keys, audit records, …), use EnqueueTx inside a caller-owned transaction instead.

func (*Store) EnqueueTx

func (s *Store) EnqueueTx(ctx context.Context, tx pgx.Tx, run worker.NewRun) error

EnqueueTx inserts a queued run inside a caller-provided pgx transaction. The caller owns the tx lifecycle (Begin, Commit, Rollback). Use this when the run insert must be atomic with writes to tables outside the store's schema — e.g., debiting a credit ledger and creating the run in one commit.

The tx must be against the same database as the Store's pool; the library does not verify this.

func (*Store) EnqueueWebhook

func (s *Store) EnqueueWebhook(ctx context.Context, delivery *worker.WebhookDelivery) error

EnqueueWebhook implements worker.WebhookStore.

func (*Store) GetActivityHistory

func (s *Store) GetActivityHistory(ctx context.Context, executionID string) ([]*workflow.ActivityLogEntry, error)

GetActivityHistory implements workflow.ActivityLogger.

func (*Store) GetRun

func (s *Store) GetRun(ctx context.Context, orgID, id string) (*runquery.Run, error)

GetRun returns a single run by ID, scoped to orgID. An empty orgID matches rows with NULL org_id (single-tenant). Returns runquery.ErrRunNotFound when no matching row exists.

func (*Store) GetStepProgress

func (s *Store) GetStepProgress(ctx context.Context, executionID string) ([]workflow.StepProgress, error)

GetStepProgress returns every step progress row recorded for an execution, ordered by started_at (NULLS LAST) then step_name. One row per (step_name, branch_id). Returns an empty slice if no rows exist. Use this on the read side to render per-step status for a run whose identity came back from runquery.Store.GetRun, which intentionally does not carry step progress.

func (*Store) HasRefund

func (s *Store) HasRefund(ctx context.Context, orgID, runID string) (bool, error)

HasRefund implements worker.CreditStore.

func (*Store) Heartbeat

func (s *Store) Heartbeat(ctx context.Context, claim *worker.Claim) error

Heartbeat implements worker.QueueStore with (claimed_by, attempt) fencing. Rows with a status other than running, or a mismatched lease, produce ErrLeaseLost.

func (*Store) IncrementTriggerAttempts

func (s *Store) IncrementTriggerAttempts(ctx context.Context, id string, errMsg string) error

IncrementTriggerAttempts implements worker.TriggerStore.

func (*Store) IncrementWebhookAttempts

func (s *Store) IncrementWebhookAttempts(ctx context.Context, id string, lastError string) error

IncrementWebhookAttempts implements worker.WebhookStore.

func (*Store) InsertTriggers

func (s *Store) InsertTriggers(ctx context.Context, triggers []worker.Trigger) error

InsertTriggers implements worker.TriggerStore.

func (*Store) ListEvents

func (s *Store) ListEvents(ctx context.Context, runID string, afterSeq int64) ([]*worker.Event, error)

ListEvents implements worker.EventStore.

func (*Store) ListPendingTriggers

func (s *Store) ListPendingTriggers(ctx context.Context, limit int) ([]worker.Trigger, error)

ListPendingTriggers implements worker.TriggerStore.

func (*Store) ListPendingWebhooks

func (s *Store) ListPendingWebhooks(ctx context.Context, limit int) ([]*worker.WebhookDelivery, error)

ListPendingWebhooks implements worker.WebhookStore.

func (*Store) ListRefundPending

func (s *Store) ListRefundPending(ctx context.Context, limit int) ([]worker.FailedRun, error)

ListRefundPending implements worker.QueueStore by joining workflow_runs against the credit ledger: runs in StatusFailed with a matching debit but no matching refund.

func (*Store) ListRuns

func (s *Store) ListRuns(ctx context.Context, orgID string, filter runquery.RunFilter) ([]*runquery.Run, *runquery.RunCursor, error)

ListRuns returns runs matching filter, ordered newest-first with keyset pagination. Returns the rows and a cursor to pass back on the next call; the cursor is nil when no more rows exist.

orgID == "" lists runs with NULL org_id (single-tenant). Pass a real org ID for scoped B2B listings.

func (*Store) LogActivity

func (s *Store) LogActivity(ctx context.Context, entry *workflow.ActivityLogEntry) error

LogActivity implements workflow.ActivityLogger.

func (*Store) MarkTriggerCompleted

func (s *Store) MarkTriggerCompleted(ctx context.Context, id string, childRunID string) error

MarkTriggerCompleted implements worker.TriggerStore.

func (*Store) MarkTriggerFailed

func (s *Store) MarkTriggerFailed(ctx context.Context, id string, errMsg string) error

MarkTriggerFailed implements worker.TriggerStore.

func (*Store) MarkTriggerProcessing

func (s *Store) MarkTriggerProcessing(ctx context.Context, id string) error

MarkTriggerProcessing implements worker.TriggerStore. Uses a compare-and-swap on status to prevent multiple workers from processing the same trigger concurrently.

func (*Store) MarkWebhookDelivered

func (s *Store) MarkWebhookDelivered(ctx context.Context, id string) error

MarkWebhookDelivered implements worker.WebhookStore.

func (*Store) MarkWebhookFailed

func (s *Store) MarkWebhookFailed(ctx context.Context, id string, errMsg string) error

MarkWebhookFailed implements worker.WebhookStore.

func (*Store) MarkWebhookProcessing

func (s *Store) MarkWebhookProcessing(ctx context.Context, id string) error

MarkWebhookProcessing implements worker.WebhookStore with a compare-and-swap to prevent duplicate delivery.

func (*Store) Migrate

func (s *Store) Migrate(ctx context.Context) error

Migrate applies the schema to the database. Idempotent: safe to call on every startup.

func (*Store) NewActivityLogger

func (s *Store) NewActivityLogger(_ *worker.Claim) workflow.ActivityLogger

NewActivityLogger returns a workflow.ActivityLogger backed by this Store for the given claim. Activity log rows are append-only and not lease-fenced.

func (*Store) NewCheckpointer

func (s *Store) NewCheckpointer(claim *worker.Claim) workflow.Checkpointer

NewCheckpointer returns a lease-fenced workflow.Checkpointer for the given claim. Writes fence on (claimed_by, attempt); a fencing failure returns worker.ErrLeaseLost from the SaveCheckpoint call.

Reads (LoadCheckpoint) are unfenced: a fresh attempt must be able to resume regardless of which worker originally wrote the snapshot.

func (*Store) NewStepProgressStore

func (s *Store) NewStepProgressStore(_ *worker.Claim) workflow.StepProgressStore

NewStepProgressStore returns a workflow.StepProgressStore backed by this Store for the given claim. The current implementation ignores the claim (progress rows are not lease-fenced) but the signature matches HandlerStores so consumers can wire it directly into a worker.

func (*Store) Pool

func (s *Store) Pool() *pgxpool.Pool

Pool returns the underlying pgxpool.Pool for queries the high-level API does not cover. Consumers are responsible for not breaking the store's invariants (lease fencing, status transitions, etc.).

func (*Store) ReclaimStale

func (s *Store) ReclaimStale(ctx context.Context, staleBefore time.Time, maxAttempts int, excludeIDs []string) (int, error)

ReclaimStale implements worker.QueueStore.

func (*Store) Refund

func (s *Store) Refund(ctx context.Context, orgID, runID, workflowType string, amount int) error

Refund implements worker.CreditStore. Idempotent per (run_id, "refund").

func (*Store) Schema

func (s *Store) Schema() string

Schema returns the configured Postgres schema name.

func (*Store) UpdateRunSpec

func (s *Store) UpdateRunSpec(ctx context.Context, claim *worker.Claim, spec []byte) error

UpdateRunSpec replaces the spec on a running claim. It fences on (claim_id, worker_id, attempt) and status = running, and returns ErrLeaseLost if the fence fails — matching Heartbeat and Complete.

Use this during long-running activities that mutate the run spec incrementally (e.g., a KB-apply loop persisting progress between steps) and need the update durable without waiting for the next checkpoint. The caller retains responsibility for producing a valid spec; the store does not inspect it.

func (*Store) UpdateStepProgress

func (s *Store) UpdateStepProgress(ctx context.Context, executionID string, p workflow.StepProgress) error

UpdateStepProgress implements workflow.StepProgressStore by upserting into workflow_step_progress. Keyed on (execution_id, step_name, branch_id) — a step running on two branches produces two rows.

Jump to

Keyboard shortcuts

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