changestore

package
v0.1.0-dev8 Latest Latest
Warning

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

Go to latest
Published: Jun 5, 2026 License: Apache-2.0 Imports: 2 Imported by: 0

README

ChangeStore

Vendor-agnostic interface for tracking per-URI claims by in-flight land requests.

Each record asserts that a specific URI (e.g., a GitHub PR) was claimed by a specific request, scoped to a queue. The store is read by the orchestrator's validate controller to detect duplicate requests — submissions whose URIs overlap with another in-flight request's URIs in the same queue.

The interface is intentionally per-record / per-URI so any backend (SQL, DynamoDB, Bigtable, …) can implement it without needing batch atomicity or multi-key query support. Callers that have multiple URIs to claim or check loop over them; the typical request has a small number of URIs (a single PR or a short stack), so the loop overhead is negligible.

Semantics

  • Identity is immutable. A record is keyed by (Queue, URI, RequestID); once written, that triple is never mutated.
  • Queue leads the key. Backends should make Queue the leading column of the primary key (or partition key, in shardable stores). All reads are queue-scoped, so this turns lookups into PK-prefix scans and keeps the table shardable.
  • RequestID in the key is intentional. Concurrent claims by different requests on the same URI coexist as distinct rows. Same-request retries collide on the PK and are absorbed idempotently; cross-request collisions show up as additional rows that callers detect via GetByURI.
  • Metadata is required and mutable. The Metadata field is JSON. The store treats '{}' as the canonical "no metadata yet" value — callers that pass an empty Go string get '{}' written. Downstream enrichment can update it; UpdatedAt reflects the last update.
  • Per-record writes, idempotent. Create writes a single record. A primary-key conflict is silently ignored, which makes queue-redelivery of the same request a safe no-op. There is no batch atomicity in the contract — callers with multiple URIs loop and rely on idempotency to converge under partial failure / retry.
  • Per-URI reads, no filtering. GetByURI returns every record for a given (queue, uri). The store does not filter by request_id or by the owning request's state. Callers that want to skip self filter by RequestID; callers that want only live owners consult RequestStore for liveness.
  • Versioned for safe metadata updates. Each record carries a Version integer (starts at 1). Future UpdateMetadata operations follow the same caller-owned-arithmetic + conditional-write pattern as RequestStore.UpdateState — the caller passes oldVersion and newVersion, and the store performs a pure conditional write.
  • Append-only by design. Records are not deleted when the owning request reaches a terminal state; the historical claim is preserved for audit. Duplicate detection filters terminals out at query time via the controller-side liveness check.

Implementing a Backend

  1. Create extension/changestore/{backend}/ directory.
  2. Implement the ChangeStore interface.
  3. Add schema files under extension/changestore/{backend}/schema/ if the backend requires them.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ChangeStore

type ChangeStore interface {
	// Create persists a single ChangeRecord. A primary-key conflict on
	// (Queue, URI, RequestID) is silently ignored, which makes the call
	// idempotent under queue redeliveries of the same request. Records belonging
	// to different requests do not conflict on the PK — cross-request overlap
	// is detected by GetByURI, not by Create.
	Create(ctx context.Context, record entity.ChangeRecord) error

	// GetByURI returns every ChangeRecord for the given (queue, uri). Multiple
	// requests can have claimed the same URI over time, so the slice may have
	// any number of entries; an empty slice means no claim has ever been
	// recorded for this URI in this queue.
	//
	// The store does not filter by request_id or by the owning request's
	// state — callers that want to skip self filter by RequestID, and callers
	// that want only live owners consult RequestStore for liveness.
	GetByURI(ctx context.Context, queue string, uri string) ([]entity.ChangeRecord, error)
}

ChangeStore manages per-URI claim records for in-flight land requests. Each row records that a specific URI was claimed by a specific request, scoped to a queue. The (Queue, URI, RequestID) triple is the immutable identity of a record. Metadata may evolve over time.

The interface is intentionally per-record / per-URI so that any backend (SQL, DynamoDB, Bigtable, …) can implement it without needing batch-atomicity or multi-key query support. Callers loop when they have multiple URIs to claim or check; the typical request has a small number of URIs (a single PR or a short stack), so the loop overhead is negligible.

Directories

Path Synopsis
Package mock is a generated GoMock package.
Package mock is a generated GoMock package.

Jump to

Keyboard shortcuts

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