Documentation
¶
Overview ¶
Package idempotency provides command deduplication for the dashboard contract: a Store interface shaped for the dispatcher, and InMemoryStore, which keeps its entries in a middleware.IdempotencyStore. That is the same store the HTTP idempotency middleware (forge.WithIdempotency) uses, so one backend can serve both. Wrappers around dispatcher.Dispatch consult the store before invoking command handlers and return cached envelopes when the (key, identity) tuple matches a recent invocation. InMemoryStore is also a Claimer: it holds a key while a command runs, through the shared store's own claims, so two overlapping dispatches with one key never both run it.
Index ¶
Constants ¶
const DefaultMaxEntries = middleware.DefaultIdempotencyMaxEntries
DefaultMaxEntries is the default cap for the store NewInMemoryStore builds.
SharedScope namespaces dashboard command keys inside a shared store, so a dashboard command and an HTTP route never collide even on one backend.
Variables ¶
var ErrClaimHeld = errors.New("idempotency: key is held by a running command")
ErrClaimHeld is what Claim's error wraps when ctx ended while another caller still held the key.
var ErrClaimLost = errors.New("idempotency: claim lapsed before it ended")
ErrClaimLost is what End's error wraps when the claim's lease lapsed before End, so the claim was swept or passed to another caller and End stored nothing. The error also wraps middleware.ErrIdempotencyNotHolder.
Functions ¶
This section is empty.
Types ¶
type Cached ¶
type Cached struct {
// Status is the HTTP status the original handler returned.
Status int
// WireBody is the JSON envelope the original handler produced, ready to
// write back verbatim.
WireBody json.RawMessage
// StoredAt is when this entry landed in the store.
StoredAt time.Time
// TTL is how long the entry is considered fresh.
TTL time.Duration
}
Cached is one cached command response.
type Claim ¶ added in v1.12.2
type Claim struct {
// Cached is the entry already stored for the key.
Cached *Cached
// End ends a claim the caller holds. Pass the entry to store under the
// claim, or nil to store nothing and give the key back. A caller that
// holds a claim must call End exactly once. When the claim lapsed before
// End, End stores nothing and its error wraps ErrClaimLost.
End func(ctx context.Context, c *Cached) error
}
Claim is what Claimer.Claim found.
type Claimer ¶ added in v1.12.2
type Claimer interface {
Store
// Claim takes (key, identity) for the caller. While another caller holds
// the key it waits for that claim to end, until ctx ends. Exactly one of
// the returned Claim's fields is set: Cached when an entry is stored for
// the key, End when the caller now holds it. When ctx ends with the key
// still held, the error wraps ErrClaimHeld.
Claim(ctx context.Context, key, identity string) (Claim, error)
}
Claimer is a Store that can also hold a key while a command runs, so two overlapping dispatches with the same key and identity never both run it. The dispatcher finds it by type assertion; a plain Store keeps working without it.
type InMemoryStore ¶
type InMemoryStore struct {
// contains filtered or unexported fields
}
InMemoryStore is the dashboard's Store as a view over a middleware.IdempotencyStore. NewInMemoryStore gives it a private in-memory backend; NewSharedStore lets it share one with the HTTP idempotency middleware. Safe for concurrent use.
func NewInMemoryStore ¶
func NewInMemoryStore(opts ...Option) *InMemoryStore
NewInMemoryStore returns a Store backed by its own in-memory middleware.IdempotencyStore.
func NewSharedStore ¶ added in v1.12.2
func NewSharedStore(shared middleware.IdempotencyStore) *InMemoryStore
NewSharedStore returns a Store that keeps its entries in shared.
func (*InMemoryStore) Claim ¶ added in v1.12.2
Claim implements Claimer over the shared store's own Begin, Complete and Release, so a dashboard command's claim is the same kind of claim an HTTP request holds.
type Option ¶
type Option func(*options)
Option configures NewInMemoryStore.
func WithMaxEntries ¶
WithMaxEntries caps the number of cached entries; oldest are evicted first.
type Store ¶
type Store interface {
Lookup(ctx context.Context, key, identity string) (*Cached, bool)
Store(ctx context.Context, key, identity string, c Cached) error
}
Store deduplicates command invocations by (key, identity) tuple. Lookup returns a cached envelope if one is present and unexpired; the dispatcher writes back the cached envelope verbatim when found. Implementations MUST be safe for concurrent use.