Documentation
¶
Overview ¶
Package idempotency provides Redis-backed claim/commit for request dedupe.
Index ¶
- Constants
- Variables
- func RedisKey(tok Token) string
- type Config
- type Fingerprint
- type Kind
- type Outcome
- type Record
- type RedisStore
- func (rs *RedisStore) Claim(ctx context.Context, tok Token, fingerprint Fingerprint) (Outcome, error)
- func (rs *RedisStore) Commit(ctx context.Context, tok Token, rec Record) error
- func (rs *RedisStore) PendingTTL() time.Duration
- func (rs *RedisStore) Release(ctx context.Context, tok Token, fingerprint Fingerprint) error
- type State
- type Store
- type Token
Constants ¶
const CurrentRecordVersion = 1
CurrentRecordVersion is the JSON schema version written by this package.
Variables ¶
var ErrNilClient = errors.New("idempotency: nil redis client")
ErrNilClient is returned when NewRedisStore is given a nil Redis client. A client is required because Claim/Complete perform network I/O against Redis.
var ErrUnsupportedVersion = fmt.Errorf("idempotency: unsupported record version")
ErrUnsupportedVersion is returned when a Redis value has an unknown schema version.
Functions ¶
Types ¶
type Config ¶
type Config struct {
TTL time.Duration // completed-record TTL (default 24h)
PendingTTL time.Duration // in-flight claim TTL (default 9m)
}
Config configures the Redis-backed store.
type Fingerprint ¶
type Fingerprint string
Fingerprint is the normalized request fingerprint bound to an idempotency key.
type Kind ¶
type Kind int
Kind is the outcome of a Claim.
const ( // KindMiss means this caller owns the in-flight claim. KindMiss Kind = iota // KindHit means a completed response is available for replay. KindHit // KindConflict means the key was used with a different request fingerprint. KindConflict // KindInProgress means another request holds the pending claim. KindInProgress )
type Record ¶
type Record struct {
Version int `json:"v"`
State State `json:"state"`
Fingerprint Fingerprint `json:"fp"`
Status int `json:"status,omitempty"`
Body []byte `json:"body,omitempty"`
}
Record is the Redis value for an idempotency key.
type RedisStore ¶
type RedisStore struct {
// contains filtered or unexported fields
}
RedisStore implements Store with Redis SETNX + optimistic CAS.
func NewRedisStore ¶
func NewRedisStore(client redis.UniversalClient, cfg Config) (*RedisStore, error)
NewRedisStore returns an org-scoped idempotency store backed by Redis. client must be non-nil; the store has no fallback transport.
func (*RedisStore) Claim ¶
func (rs *RedisStore) Claim(ctx context.Context, tok Token, fingerprint Fingerprint) (Outcome, error)
Claim implements Store.
func (*RedisStore) PendingTTL ¶
func (rs *RedisStore) PendingTTL() time.Duration
PendingTTL returns the in-flight claim TTL (tests).
func (*RedisStore) Release ¶
func (rs *RedisStore) Release(ctx context.Context, tok Token, fingerprint Fingerprint) error
Release implements Store.
type Store ¶
type Store interface {
// Claim reserves or inspects the key for tok.
// A non-nil error is an infrastructure failure (caller should fail-open).
Claim(ctx context.Context, tok Token, fingerprint Fingerprint) (Outcome, error)
// Commit stores a completed record only when the key is still pending with the same fingerprint.
Commit(ctx context.Context, tok Token, rec Record) error
// Release deletes a pending claim with matching fingerprint so a later retry can reclaim.
Release(ctx context.Context, tok Token, fingerprint Fingerprint) error
}
Store claims and commits org-scoped idempotency keys.