persist

package
v0.9.0 Latest Latest
Warning

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

Go to latest
Published: Jul 9, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package persist wires AgentGuard's in-memory fast-path state to a durable store.Store using the write-behind dual-tier model (docs/v0.6-ARCHITECTURE- PLAN.md §2.3–2.4).

The Syncer is the ONLY component that bridges memory and disk. It:

  • Hydrate(): on boot, loads persisted state back into the in-memory maps (rate-limit buckets, session-cost accumulators, approval queue) so a restart does not lose them.
  • flush loop: on a ticker with a hard 1s floor, snapshots each in-memory structure and upserts it to the store. This runs on its own goroutine and NEVER touches the /v1/check request path, so the <3ms latency budget is unaffected (CLAUDE.md rule #1).
  • purge loop: periodically GCs stale rows (resolved approvals, idle costs, fully-refilled buckets), mirroring the in-memory eviction.
  • Close(): stops the loops and performs one final flush so the last second of state is durable across a graceful shutdown.

Index

Constants

View Source
const DefaultPurgeInterval = 1 * time.Minute

DefaultPurgeInterval is how often stale rows are GC'd. Much coarser than the flush — GC is housekeeping, not durability.

View Source
const MinFlushInterval = 1 * time.Second

MinFlushInterval is the hard floor on the flush cadence (plan §2.4): the syncer never writes more often than once per second, bounding write amplification / WAL churn.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	Store     store.Store
	Limiter   *ratelimit.Limiter
	Engine    *policy.Engine
	Approvals *proxy.ApprovalQueue

	// FlushInterval is clamped up to MinFlushInterval. Zero => MinFlushInterval.
	FlushInterval time.Duration
	// PurgeInterval is how often GC runs. Zero => DefaultPurgeInterval.
	PurgeInterval time.Duration

	// Retention cutoffs for GC. Zero disables that purge (rows kept forever).
	CostTTL     time.Duration // idle session-cost rows
	ApprovalTTL time.Duration // resolved approvals
	BucketTTL   time.Duration // fully-refilled buckets
}

Config wires the syncer to the store and the in-memory sources. Any source may be nil (that slice is simply skipped), which keeps the syncer usable in focused tests.

type Syncer

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

Syncer drives the write-behind loops.

func New

func New(cfg Config) *Syncer

New builds a Syncer, clamping the flush interval to the 1s floor.

func (*Syncer) Close

func (s *Syncer) Close()

Close stops the loops, waits for the goroutine to exit, then performs one final flush so the last interval of state is durable. Idempotent.

func (*Syncer) Flush

func (s *Syncer) Flush(ctx context.Context) error

Flush snapshots every in-memory source and upserts it to the store in one pass. Exposed (rather than purely internal) so tests and the shutdown path can force a synchronous flush. Safe to call concurrently with the flush loop only via Close (which stops the loop first).

func (*Syncer) Hydrate

func (s *Syncer) Hydrate(ctx context.Context) error

Hydrate loads persisted state into the in-memory structures. Call once, on boot, BEFORE the server starts serving traffic. A store read error is returned so the operator can decide whether to proceed with empty state.

func (*Syncer) Purge

func (s *Syncer) Purge(ctx context.Context, now time.Time) error

Purge GCs stale rows relative to now. Each TTL of 0 disables its purge.

func (*Syncer) Start

func (s *Syncer) Start()

Start launches the flush + purge goroutines. Hydrate first.

Jump to

Keyboard shortcuts

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