persistence

package
v1.1.4 Latest Latest
Warning

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

Go to latest
Published: Jul 20, 2026 License: MIT Imports: 10 Imported by: 0

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

Constants

This section is empty.

Variables

View Source
var ErrKeyNotFound = errors.New("key not found")

ErrKeyNotFound is returned by Load when the requested key does not exist.

Functions

func MarshalSnapshot

func MarshalSnapshot(ctx context.Context, service string, v any) []byte

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

func UnmarshalSnapshot(ctx context.Context, service string, data []byte, v any) error

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

func NewFileStore(baseDir string) (*FileStore, error)

NewFileStore creates a FileStore rooted at baseDir. The directory is created (with parents) if it does not exist.

func (*FileStore) Delete

func (f *FileStore) Delete(service, key string) error

Delete removes {baseDir}/{service}/{key}.json. It is not an error if the file does not exist.

func (*FileStore) ListKeys

func (f *FileStore) ListKeys(service string) ([]string, error)

ListKeys returns the base names (without .json extension) of all files under {baseDir}/{service}/. Temp files created during atomic saves are excluded.

func (*FileStore) Load

func (f *FileStore) Load(service, key string) ([]byte, error)

Load reads data from {baseDir}/{service}/{key}.json. Returns ErrKeyNotFound when the file does not exist.

func (*FileStore) Save

func (f *FileStore) Save(service, key string, data []byte) error

Save writes data to {baseDir}/{service}/{key}.json.

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

func NewManager(ctx context.Context, store Store) *Manager

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

func (m *Manager) ExportAll() map[string][]byte

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

func (m *Manager) ImportAll(ctx context.Context, snapshots map[string][]byte) error

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

func (m *Manager) Notify(name string)

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:

  1. A previously-fired AfterFunc whose closure captured an old generation racing with a newer Notify (the old fire is skipped by the gen check).
  2. 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

func (m *Manager) RestoreAll(ctx context.Context)

RestoreAll loads and restores snapshots for all registered Persistable backends. Errors for individual services are logged but do not abort restoration of others.

func (*Manager) SaveAll

func (m *Manager) SaveAll(ctx context.Context)

SaveAll immediately persists all registered backends. Pending debounce timers are stopped to prevent concurrent writes on shutdown. It is intended for graceful shutdown.

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.

func (NullStore) Delete

func (NullStore) Delete(_, _ string) error

Delete is a no-op.

func (NullStore) ListKeys

func (NullStore) ListKeys(_ string) ([]string, error)

ListKeys always returns an empty slice.

func (NullStore) Load

func (NullStore) Load(_, _ string) ([]byte, error)

Load always returns ErrKeyNotFound.

func (NullStore) Save

func (NullStore) Save(_, _ string, _ []byte) error

Save is a no-op.

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.

Jump to

Keyboard shortcuts

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