Help us shape the future of Go! Take the 2026 Go Developer Survey

sidecar

package
v0.21.0 Latest Latest
Warning

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

Go to latest
Published: Oct 29, 2026 License: AGPL-3.0 Imports: 11 Imported by: 0

Documentation

Overview

Package sidecar is the durable-file discipline Atlas's design-time stores share.

Deployments, drafts, projects, forms, workers, the secret vault and the rest all persist small records as one file per key under a directory (ADR-0019, ADR-0021). They differ in what they store and agree completely on how to put it on disk: temp file, fsync, rename, fsync the directory. That sequence lives here once, so "nil error means the record is durable" is one implementation rather than sixteen — the same durable-before-visible rule the engine's log follows (I2 / ADR-0005), applied to the sidecar files beside it.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func FsyncDir

func FsyncDir(dir string) error

FsyncDir fsyncs a directory so a create/rename/remove of a file within it is itself durable.

func WriteFile

func WriteFile(dir, path string, data []byte) error

WriteFile writes raw bytes to path with the same discipline WriteJSON gives a record. It exists because not every durable artifact is JSON — a process documentation PDF (ADR-0143) is opaque bytes stored beside its sidecar, and it deserves the same "nil error means on disk" guarantee.

func WriteJSON

func WriteJSON(dir, path string, v any) error

WriteJSON marshals v and writes it to path atomically: temp file → fsync → rename → dir fsync. On return with nil error the record is durable, so a caller may treat it as saved (durable before visible, I2 / ADR-0005).

Types

type Option

type Option[T any] func(*Store[T])

Option configures a Store at construction. The defaults cover the common case (hex-encoded filenames, listing in filename order); an option is only needed where a store genuinely differs.

func Names

func Names[T any](enc func(string) string, ok func(string) bool) Option[T]

Names replaces the default filename scheme. enc maps a record's key to its filename stem, and ok reports whether a stem found in the directory is one of this store's records — the guard that lets an unrelated file share the directory without breaking a listing.

The default hex-encodes the key, which is what makes an arbitrary BPMN id or email address a safe, unique, deterministic filename. Override it only when the key is already filename-safe *and* recognizable: a hex token, a decimal entity key.

func Order

func Order[T any](less func(a, b T) bool) Option[T]

Order sets the order LoadAll returns records in. Without it a listing comes back in filename order, which is stable but arbitrary; with it a store states the order its UI expects — newest-first for drafts, creation order for projects. less has sort.Slice semantics.

type Store

type Store[T any] struct {
	// contains filtered or unexported fields
}

Store is a durable store for one kind of design-time record: one JSON file per key under a single directory, written with the durability discipline above.

Atlas has sixteen of these — drafts, projects, forms, workers, deployments, releases, users, deploy tokens and the rest. They differ in what they store, how a record names itself, and what order a listing comes back in. They agreed on everything else, which is what this type now holds: create the directory, encode the key into a safe filename, write atomically, read back, ignore files that are not ours, delete idempotently.

Like the stores it replaces, a Store does no locking of its own, and it needs none: it keeps no mutable memory, so every method is a syscall against the directory. Writing is still the run-loop goroutine's alone — it is the single writer of design-time state, and a check-then-write ("is this username taken?") is atomic only because both halves happen inside one loop turn.

Reading is not confined to the loop. A record is replaced by an atomic rename (see WriteJSON), so a concurrent reader sees the whole old record or the whole new one and never a torn one, and a temp file is not named like a record so a listing never picks one up. A caller that must not wait for the engine may therefore read directly — which is what keeps signing in independent of how busy the processor is (ADR-0265).

func NewStore

func NewStore[T any](dir, name string, key func(T) string, opts ...Option[T]) (*Store[T], error)

NewStore opens (creating if needed) the directory backing a store. name is the prefix every error from this store carries, so a failure names the store it came from; key extracts a record's identity, which is what Save files it under.

func (*Store[T]) Delete

func (s *Store[T]) Delete(key string) error

Delete removes the record filed under key. A missing record — or a key that could never name one — is not an error, so cleanup is idempotent.

func (*Store[T]) Dir

func (s *Store[T]) Dir() string

Dir is the directory the store's records live in. Callers that keep sibling artifacts beside a record — a documentation PDF (ADR-0143) — need it.

func (*Store[T]) FileFor

func (s *Store[T]) FileFor(key string) string

FileFor maps a key to its record path. It is a pure path helper and does not check the key — the entry points below do that; call it only with a key you have already addressed the store with.

func (*Store[T]) Get

func (s *Store[T]) Get(key string) (T, bool, error)

Get returns the record filed under key, or ok=false if there is none. A missing record is a normal state, not an error, and so is a key that could never name one.

func (*Store[T]) LoadAll

func (s *Store[T]) LoadAll() ([]T, error)

LoadAll reads every record in the store, in the order set by Order. Files that are not this store's records — a stray temp file, a sibling artifact, a subdirectory — are skipped rather than failing the listing, and so is a record deleted between the listing and its read, which is what a reader running off the run loop can meet.

func (*Store[T]) Save

func (s *Store[T]) Save(rec T) error

Save writes a record durably, overwriting any record already filed under the same key. On return with nil error it is on disk (I2 / ADR-0005). A record whose key could not name a file in this store is refused rather than written.

Jump to

Keyboard shortcuts

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