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

store

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Oct 9, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrConflict = errors.New("conflicting replay")
View Source
var ErrEndpointConflict = errors.New("endpoint version or rotation precondition failed")
View Source
var ErrIdempotencyConflict = errors.New("idempotency key conflicts with accepted event")
View Source
var ErrIdempotencyExpired = errors.New("idempotency receipt expired during request")
View Source
var ErrInvalidBatch = errors.New("invalid recovery selection")
View Source
var ErrInvalidSearch = errors.New("invalid search filters or cursor")
View Source
var ErrMasterKey = errors.New("master key does not match database")
View Source
var ErrNotFound = errors.New("not found")
View Source
var LatencyBuckets = []float64{0.005, 0.025, 0.1, 0.5, 1, 2, 5, 10, 30, 60}

Functions

func ValidIdempotencyKey

func ValidIdempotencyKey(key string) bool

Types

type Attempt

type Attempt struct {
	RetryBaseSeconds  int        `json:"retry_base_seconds"`
	RetryCapSeconds   int        `json:"retry_cap_seconds"`
	ExpiresAt         *time.Time `json:"expires_at,omitempty"`
	EndpointVersion   *int64     `json:"endpoint_version,omitempty"`
	SigningVersion    *int64     `json:"signing_version,omitempty"`
	ReplayPrincipalID *string    `json:"replay_principal_id,omitempty"`
	TraceParent       string     `json:"trace_parent,omitempty"`
	AttemptNumber     int        `json:"attempt_number"`
	CycleAttempt      int        `json:"cycle_attempt"`
	MaxAttempts       int        `json:"max_attempts"`
	AvailableAt       time.Time  `json:"available_at"`
	Retryable         *bool      `json:"retryable,omitempty"`
	ReplayOf          *string    `json:"replay_of,omitempty"`
	ReplayRequestID   *string    `json:"replay_request_id,omitempty"`
	ReplayActor       *string    `json:"replay_actor,omitempty"`
	ReplayReason      *string    `json:"replay_reason,omitempty"`
	ID                string     `json:"id"`
	EventID           string     `json:"event_id"`
	State             string     `json:"state"`
	ClaimCount        int        `json:"claim_count"`
	LastStartedAt     *time.Time `json:"last_started_at,omitempty"`
	CompletedAt       *time.Time `json:"completed_at,omitempty"`
	ResponseStatus    *int       `json:"response_status,omitempty"`
	ErrorCode         *string    `json:"error_code,omitempty"`
	ErrorMessage      *string    `json:"error_message,omitempty"`
	CreatedAt         time.Time  `json:"created_at"`
	UpdatedAt         time.Time  `json:"updated_at"`
}

type BatchItem

type BatchItem struct {
	ReplaySelection
	PreviewState    string     `json:"preview_state"`
	PreviewEligible bool       `json:"preview_eligible"`
	Result          string     `json:"result"`
	ReplayAttemptID *string    `json:"replay_attempt_id,omitempty"`
	CompletedAt     *time.Time `json:"completed_at,omitempty"`
}

type BatchRequest

type BatchRequest struct {
	RequestID   string            `json:"request_id"`
	Reason      string            `json:"reason"`
	Events      []ReplaySelection `json:"events"`
	PrincipalID string            `json:"-"`
	Actor       string            `json:"-"`
}

type ClaimedDelivery

type ClaimedDelivery struct {
	RetryBaseSeconds int
	RetryCapSeconds  int
	ExpiresAt        *time.Time
	EndpointVersion  int64
	SigningVersion   int64
	TraceParent      string
	QueuedAt         time.Time
	AvailableAt      time.Time
	CycleAttempt     int
	LeaseUntil       time.Time
	AttemptID        string
	EventID          string
	EventType        string
	Payload          []byte
	EndpointID       string
	EndpointURL      string
	SecretCiphertext []byte
	ClaimCount       int
}

type Endpoint

type Endpoint struct {
	Version                int64      `json:"version"`
	Paused                 bool       `json:"paused"`
	SigningVersion         int64      `json:"signing_version"`
	RetiringSigningVersion *int64     `json:"retiring_signing_version,omitempty"`
	RetireAfter            *time.Time `json:"retire_after,omitempty"`
	RetryBaseSeconds       int        `json:"retry_base_seconds"`
	RetryCapSeconds        int        `json:"retry_cap_seconds"`
	EventTTLSeconds        int        `json:"event_ttl_seconds"`
	CreatedBy              string     `json:"created_by,omitempty"`
	MaxAttempts            int        `json:"max_attempts"`
	ConcurrencyLimit       int        `json:"concurrency_limit"`
	RateLimit              int        `json:"rate_limit"`
	ID                     string     `json:"id"`
	URL                    string     `json:"url"`
	CreatedAt              time.Time  `json:"created_at"`
}

type EndpointAudit

type EndpointAudit struct {
	Version       int64     `json:"version"`
	PrincipalID   string    `json:"principal_id,omitempty"`
	Action        string    `json:"action"`
	Reason        string    `json:"reason"`
	Configuration Endpoint  `json:"configuration"`
	CreatedAt     time.Time `json:"created_at"`
}

type EndpointChange

type EndpointChange struct {
	ExpectedVersion int64
	PrincipalID     string
	Reason          string
	Action          string
	Settings        Endpoint
	Ciphertext      []byte
	Overlap         time.Duration
}

type Event

type Event struct {
	ProducerReference string    `json:"producer_reference,omitempty"`
	ID                string    `json:"id"`
	EndpointID        string    `json:"endpoint_id"`
	EventType         string    `json:"event_type"`
	State             string    `json:"state"`
	CreatedAt         time.Time `json:"created_at"`
}

type EventFilter

type EventFilter struct {
	EndpointID        string     `json:"endpoint_id,omitempty"`
	From              *time.Time `json:"from,omitempty"`
	Until             *time.Time `json:"until,omitempty"`
	State             string     `json:"state,omitempty"`
	ProducerReference string     `json:"producer_reference,omitempty"`
}

type EventPage

type EventPage struct {
	Events    []Investigation `json:"events"`
	NextAfter string          `json:"next_after,omitempty"`
}

type Histogram

type Histogram struct {
	Count   uint64
	Sum     float64
	Buckets map[float64]uint64
}

type IngestionReceipt

type IngestionReceipt struct {
	Event     Event
	AttemptID string
	Repeated  bool
}

IngestionReceipt is the original acceptance, not the event's current state.

type Investigation

type Investigation struct {
	Event
	AttemptID      string     `json:"attempt_id"`
	AttemptNumber  int        `json:"attempt_number"`
	NextAttemptAt  *time.Time `json:"next_attempt_at,omitempty"`
	ExpiresAt      *time.Time `json:"expires_at,omitempty"`
	Paused         bool       `json:"paused"`
	FailureCode    string     `json:"failure_code,omitempty"`
	FailureSummary string     `json:"failure_summary,omitempty"`
	ResponseStatus *int       `json:"response_status,omitempty"`
}

type MetricsSnapshot

type MetricsSnapshot struct {
	WorkersRecent              int64
	WorkerPollAgeSeconds       float64
	WorkerCompletionAgeSeconds float64
	DatabaseBytes              int64
	Events                     int64
	Claims                     int64
	Recoveries                 int64
	Retries                    int64
	Replays                    int64
	Queue                      map[string]int64
	States                     map[string]int64
	Completed                  map[string]int64
	OldestReadySeconds         float64
	Latency                    map[string]Histogram
}

type Outcome

type Outcome struct {
	Status  int
	Code    string
	Message string
	RetryAt *time.Time
}

type ReplayBatch

type ReplayBatch struct {
	ID          string      `json:"id"`
	PrincipalID string      `json:"principal_id"`
	Reason      string      `json:"reason"`
	CreatedAt   time.Time   `json:"created_at"`
	StartedAt   *time.Time  `json:"started_at,omitempty"`
	State       string      `json:"state"`
	Items       []BatchItem `json:"items"`
}

type ReplayRequest

type ReplayRequest struct {
	AttemptID   string `json:"attempt_id"`
	RequestID   string `json:"request_id"`
	Actor       string `json:"-"`
	PrincipalID string `json:"-"`
	Reason      string `json:"reason"`
}

type ReplayResult

type ReplayResult struct {
	AttemptID string `json:"attempt_id"`
	EventID   string `json:"event_id"`
	RequestID string `json:"request_id"`
}

type ReplaySelection

type ReplaySelection struct {
	EventID   string `json:"event_id"`
	AttemptID string `json:"attempt_id"`
}

type RetentionResult

type RetentionResult struct {
	Events    int64     `json:"events"`
	Batches   int64     `json:"batches"`
	AuditRows int64     `json:"audit_rows"`
	Applied   bool      `json:"applied"`
	Cutoff    time.Time `json:"cutoff"`
}

type Store

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

func Open

func Open(ctx context.Context, databaseURL string) (*Store, error)

func (*Store) Authenticate

func (s *Store) Authenticate(ctx context.Context, hash []byte, now time.Time) (auth.Principal, error)

func (*Store) ChangeEndpoint

func (s *Store) ChangeEndpoint(ctx context.Context, endpointID string, change EndpointChange, now time.Time) (Endpoint, error)

ChangeEndpoint shares the claim lock. A committed pause prevents later claims; claims committed before it keep their captured destination and signing key.

func (*Store) CheckMasterKey

func (s *Store) CheckMasterKey(ctx context.Context, box *secret.Box) error

CheckMasterKey binds even an empty database to its wrapping key. On upgrade, every existing endpoint must decrypt before the marker can be initialized.

func (*Store) ClaimAvailable

func (s *Store) ClaimAvailable(ctx context.Context, workerID string, now time.Time, lease time.Duration, limit int) ([]ClaimedDelivery, error)

ClaimAvailable reserves endpoint capacity and rate permits in the same transaction as attempt leases. All workers share these PostgreSQL counters.

func (*Store) Close

func (s *Store) Close()

func (*Store) Complete

func (s *Store) Complete(ctx context.Context, claim ClaimedDelivery, workerID string, now time.Time, outcome Outcome) (bool, error)

Complete fences every result with the claim generation and an unexpired lease. A failed result and its successor commit together or neither does.

func (*Store) CreateEndpoint

func (s *Store) CreateEndpoint(ctx context.Context, endpoint Endpoint, secretCiphertext []byte) error

func (*Store) CreateEvent

func (s *Store) CreateEvent(ctx context.Context, event Event, payload []byte, attemptID string) error

CreateEvent atomically records the exact payload bytes and its first attempt.

func (*Store) CreatePrincipal

func (s *Store) CreatePrincipal(ctx context.Context, p auth.Principal, now time.Time) error

func (*Store) EndpointExists

func (s *Store) EndpointExists(ctx context.Context, endpointID string) (bool, error)

func (*Store) GetBatch

func (s *Store) GetBatch(ctx context.Context, batchID string) (ReplayBatch, error)

func (*Store) GetEndpoint

func (s *Store) GetEndpoint(ctx context.Context, endpointID string) (Endpoint, error)

func (*Store) GetEvent

func (s *Store) GetEvent(ctx context.Context, eventID string) (Event, error)

func (*Store) IngestEvent

func (s *Store) IngestEvent(ctx context.Context, event Event, payload []byte, attemptID, principalID, key string) (IngestionReceipt, error)

IngestEvent reserves a scoped key and commits event + attempt in the same transaction. The unique index serializes concurrent submissions of that key.

func (*Store) IssueCredential

func (s *Store) IssueCredential(ctx context.Context, principalID, credentialID string, hash []byte, now, expires time.Time) error

func (*Store) ListAttempts

func (s *Store) ListAttempts(ctx context.Context, eventID string) ([]Attempt, error)

func (*Store) ListDeadLetters

func (s *Store) ListDeadLetters(ctx context.Context, after string) ([]Event, error)

ListDeadLetters returns only events whose latest attempt exhausted its budget.

func (*Store) ListEndpointAudit

func (s *Store) ListEndpointAudit(ctx context.Context, endpointID string, after int64) ([]EndpointAudit, error)

func (*Store) ListEndpoints

func (s *Store) ListEndpoints(ctx context.Context, after string) ([]Endpoint, error)

func (*Store) Metrics

func (s *Store) Metrics(ctx context.Context, now time.Time) (MetricsSnapshot, error)

Metrics reads transactional cumulative totals and retained-state gauges from one snapshot. The HTTP caller supplies a deadline, never stale zeroes.

func (*Store) Migrate

func (s *Store) Migrate(ctx context.Context, now time.Time) error

func (*Store) PreviewBatch

func (s *Store) PreviewBatch(ctx context.Context, input BatchRequest, now time.Time) (ReplayBatch, error)

PreviewBatch freezes a bounded explicit selection without scheduling delivery. Reusing its ID with the same creator, reason, and set returns durable progress.

func (*Store) Ready

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

func (*Store) Replay

func (s *Store) Replay(ctx context.Context, eventID string, input ReplayRequest, now time.Time) (ReplayResult, error)

Replay requires the current failed attempt as a precondition. Its request ID makes repeated submissions safe even after the replay has finished.

func (*Store) Retain

func (s *Store) Retain(ctx context.Context, now time.Time, days, limit int, apply bool) (RetentionResult, error)

Retain deletes bounded groups in separate transactions. One event's complete history is indivisible; the caller's context bounds unusually large histories. Counts are committed progress (or candidate counts when apply=false).

func (*Store) RevokeCredential

func (s *Store) RevokeCredential(ctx context.Context, credentialID string, now time.Time) error

RevokeCredential is idempotent and commits the revocation with its audit row.

func (*Store) RotateMasterKey

func (s *Store) RotateMasterKey(ctx context.Context, old, next *secret.Box, now time.Time, apply bool) (int, error)

RotateMasterKey requires all API and worker processes to be stopped. Table locking protects the transaction, not already-running processes' cached keys.

func (*Store) RunBatch

func (s *Store) RunBatch(ctx context.Context, batchID, principalID string, now time.Time) (ReplayBatch, error)

RunBatch commits at most ten items per call. Only the creating principal can confirm/resume; every HTTP call reauthenticates. No job continues in background.

func (*Store) SearchEvents

func (s *Store) SearchEvents(ctx context.Context, f EventFilter, after string, limit int) (EventPage, error)

SearchEvents uses immutable creation time and UUID as a keyset. State is live, not a snapshot across pages. No payload, key, URL, or raw error is selected.

Jump to

Keyboard shortcuts

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