Documentation
¶
Overview ¶
Package persistence provides a pluggable persistence layer for Gopherstack services. Services implement the Persistable interface to participate in snapshot-based state serialisation. The Store interface abstracts the underlying storage medium.
Index ¶
- Variables
- func MarshalSnapshot(ctx context.Context, service string, v any) []byte
- func UnmarshalSnapshot(ctx context.Context, service string, data []byte, v any) error
- type FileStore
- type Manager
- func (m *Manager) ExportAll() map[string][]byte
- func (m *Manager) ImportAll(ctx context.Context, snapshots map[string][]byte) error
- func (m *Manager) Notify(name string)
- func (m *Manager) Register(name string, p Persistable)
- func (m *Manager) RestoreAll(ctx context.Context)
- func (m *Manager) SaveAll(ctx context.Context)
- type NullStore
- type Persistable
- type Store
Constants ¶
This section is empty.
Variables ¶
var ErrKeyNotFound = errors.New("key not found")
ErrKeyNotFound is returned by Load when the requested key does not exist.
Functions ¶
func MarshalSnapshot ¶
MarshalSnapshot serialises v to JSON for a service-state snapshot.
On success it emits a debug record (silent at the default info level) and returns the encoded bytes. On failure it logs a warning and returns nil, matching the Persistable.Snapshot contract (a nil snapshot is skipped by the persistence Manager). Centralising this here keeps every backend's Snapshot method consistent and gives the ctx parameter a purpose.
func UnmarshalSnapshot ¶
UnmarshalSnapshot decodes a service-state snapshot from data into v.
On success it emits a debug record; on failure it logs a warning and returns the decode error. Centralising this here keeps every backend's Restore method consistent and gives the ctx parameter a purpose.
Types ¶
type FileStore ¶
type FileStore struct {
// contains filtered or unexported fields
}
FileStore persists blobs as JSON files on the local file system. Data is stored at {baseDir}/{service}/{key}.json.
func NewFileStore ¶
NewFileStore creates a FileStore rooted at baseDir. The directory is created (with parents) if it does not exist.
func (*FileStore) Delete ¶
Delete removes {baseDir}/{service}/{key}.json. It is not an error if the file does not exist.
func (*FileStore) ListKeys ¶
ListKeys returns the base names (without .json extension) of all files under {baseDir}/{service}/. Temp files created during atomic saves are excluded.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager coordinates persistence for a set of named service backends. It restores state on startup and performs debounced async saves on mutation.
func NewManager ¶
NewManager creates a Manager backed by the given Store. The supplied context is the process lifecycle context; it carries the root logger and is used for the debounced async save path (Notify -> AfterFunc), which has no per-request or per-call context of its own. A nil ctx falls back to context.Background().
func (*Manager) ExportAll ¶
ExportAll captures an in-memory snapshot from every registered service and returns the results as a map of service name → raw snapshot bytes. Services that return an empty snapshot (nil or zero-length) are omitted from the map. The store is not written; this is a pure read of current in-memory state.
func (*Manager) ImportAll ¶
ImportAll restores state for every service whose name appears in snapshots. Services not registered with the manager are warned and skipped. Restore errors are collected; all services in the map are attempted regardless of earlier failures. Returns a combined error if any restore failed, nil otherwise.
func (*Manager) Notify ¶
Notify schedules a debounced save for the named service. If no service with that name is registered the call is a no-op.
Each Notify bumps a per-entry generation counter, stops any pending timer, and starts a fresh AfterFunc that captures the new generation. The save callback only proceeds if the generation it was created with is still the current one. This prevents two pathological cases:
- A previously-fired AfterFunc whose closure captured an old generation racing with a newer Notify (the old fire is skipped by the gen check).
- Notify being called multiple times during the debounce window: only the most recent timer's closure will pass the generation check and perform the save.
Earlier versions of this function captured the generation only on the first Notify and reused the same AfterFunc via Reset, which caused the captured generation to fall stale and the eventual save to be skipped indefinitely after a second Notify.
func (*Manager) Register ¶
func (m *Manager) Register(name string, p Persistable)
Register associates a named Persistable with the manager. It must be called before RestoreAll or Notify.
func (*Manager) RestoreAll ¶
RestoreAll loads and restores snapshots for all registered Persistable backends. Errors for individual services are logged but do not abort restoration of others.
type NullStore ¶
type NullStore struct{}
NullStore is a no-op Store that preserves zero-persistence behaviour. It is the default when PERSIST is not set.
type Persistable ¶
type Persistable interface {
Snapshot(ctx context.Context) []byte
Restore(ctx context.Context, data []byte) error
}
Persistable is an optional interface that service backends may implement to participate in Gopherstack's snapshot-based persistence.
Snapshot returns an opaque JSON blob representing current backend state. Restore initialises backend state from a previously-captured blob.
Both methods receive a context so they log through the context-aware logger (logger.Load(ctx)) — the persistence Manager threads a context tagged worker=<service>-persistence — instead of the global slog.Default().
type Store ¶
type Store interface {
// Save persists data for the given service and key.
Save(service, key string, data []byte) error
// Load retrieves data for the given service and key.
// Returns ErrKeyNotFound when the key does not exist.
Load(service, key string) ([]byte, error)
// Delete removes the data for the given service and key.
// It is not an error to delete a non-existent key.
Delete(service, key string) error
// ListKeys returns all keys stored for the given service.
ListKeys(service string) ([]string, error)
}
Store is the persistence back-end abstraction. Save/Load/Delete operate on named blobs identified by (service, key). ListKeys returns all keys stored for a service.