plug

package
v0.59.0 Latest Latest
Warning

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

Go to latest
Published: Nov 3, 2026 License: MIT Imports: 10 Imported by: 0

README

plug

import "github.com/kitsunium/sdk/framework/internal/app/plug"

Package plug is where the framework's opt-in subsystems plug in: the HTTP engine, the frontends' file server and the process sampler of the runtime graph (framework/app/server), the Studio — the tool's variables, its routes and the framework's sentences in the languages after English (framework/app/studio) —, the stores and the databases (framework/app/store), the queues (framework/app/queue), the workflows (framework/app/workflow), the mailers (framework/app/mail), the jobs (framework/app/jobs). The framework reads what they registered through the hooks declared here, and imports none of the SDK packages behind them: a product that does not import a subsystem neither links nor initialises its packages.

It is also the contract between the framework's core and the subsystems ADR 0179 takes out of it, as database/sql/driver is between database/sql and a driver: the store subsystem's engine over documents, its siblings, the framework's scope on a database and its migrations (Stores), which framework/app/store sets; the refusals an engine says in the framework's terms (Refusal); what the framework's transactions offer an engine that takes part in them (Transaction); the queue subsystem's brokers and their consumer (Queues), which framework/app/queue sets; the workflow subsystem's engine and the ports it runs on (Workflows), which framework/app/workflow sets; the mail subsystem's outbox and transports (Mail), which framework/app/mail sets; the jobs subsystem's schedules and scheduler (Jobs), which framework/app/jobs sets; the framework's catalogues in the languages after English (Words), and the Studio's routes and the tool's variables (Studio, ADR 0180 step 1), which framework/app/studio sets, the routes reading the running app through a StudioHost the framework gives.

The package imports the standard library and the framework's model only, so that the framework and every subsystem can import it.

Index

Constants

const LabelLoop string = "app_loop"

LabelLoop is the pprof label naming the loop a goroutine belongs to.

const LabelNode string = "app_node"

LabelNode is the pprof label naming the node a goroutine works for.

const MailEventDeadLettered MailEvent = 4

MailEventDeadLettered is a mail given up on after its last attempt.

const MailEventDuplicate MailEvent = 5

MailEventDuplicate is a redelivery of a mail already sent, dropped.

const MailEventOther MailEvent = 0

MailEventOther is an event of the spool the framework shows nothing of.

const MailEventQueued MailEvent = 1

MailEventQueued is a mail put in the outbox.

const MailEventRetrying MailEvent = 3

MailEventRetrying is a failed attempt that will be retried.

const MailEventSent MailEvent = 2

MailEventSent is a mail the transport accepted.

const MailGivenUpExhausted MailGiveUp = 0

MailGivenUpExhausted is a mail whose last attempt failed.

const MailGivenUpExpired MailGiveUp = 2

MailGivenUpExpired is a mail whose attempt failed once it was older than the spool's MaxAge.

const MailGivenUpRejected MailGiveUp = 1

MailGivenUpRejected is a mail the receiving server refused for good, an SMTP 5xx reply, dead-lettered without a retry.

const MailRefusalClosed MailRefusal = 1

MailRefusalClosed is a spool that is closed: its mailer is not running.

const MailRefusalInvalidURL MailRefusal = 3

MailRefusalInvalidURL is an SMTP URL that is not one of the form smtp://user:password@host:port; its "problem" field says the clause.

const MailRefusalNone MailRefusal = 0

MailRefusalNone is no refusal the framework words.

const MailRefusalUnencodable MailRefusal = 2

MailRefusalUnencodable is a mail the outbox cannot encode.

const OTLPBlock string = "block"

OTLPBlock makes the producer wait for room, up to a bound.

const OTLPDropNewest string = "drop-newest"

OTLPDropNewest refuses the new batch.

const OTLPDropOldest string = "drop-oldest"

OTLPDropOldest takes the oldest batches out until the new one fits.

const OTLPMetrics string = "metrics"

OTLPMetrics names the metrics signal: an OTLP/JSON ExportMetricsServiceRequest.

const OTLPTraces string = "traces"

OTLPTraces names the trace signal: an OTLP/JSON ExportTraceServiceRequest.

const RefusalClosed Refusal = 13

RefusalClosed is a call on a closed engine.

const RefusalExists Refusal = 2

RefusalExists is a document already under the key an insertion names.

const RefusalIndexBroken Refusal = 8

RefusalIndexBroken is stored documents that break a unique index.

const RefusalIndexNotUnique Refusal = 7

RefusalIndexNotUnique is a lookup on an index that is not unique.

const RefusalIndexUnknown Refusal = 6

RefusalIndexUnknown is an index the store does not declare.

const RefusalKeyChanged Refusal = 5

RefusalKeyChanged is an update that changes the document's key.

const RefusalKeyEmpty Refusal = 4

RefusalKeyEmpty is a document whose key is empty.

const RefusalKeyTooLong Refusal = 18

RefusalKeyTooLong is a key longer than a database's key columns hold; its "max" field says how long they hold.

const RefusalLoad Refusal = 12

RefusalLoad is a store that could not be loaded; its "problem" field says why.

const RefusalNone Refusal = 0

RefusalNone is no refusal the framework words.

const RefusalNotFound Refusal = 1

RefusalNotFound is no document under the key, or under the index's key.

const RefusalNotTrashed Refusal = 17

RefusalNotTrashed is no record in the trash under the key.

const RefusalOutOfOrder Refusal = 22

RefusalOutOfOrder is a migration older than one already applied; its "applied" field names the newer.

const RefusalPersist Refusal = 11

RefusalPersist is a write the store could not keep.

const RefusalRenameTarget Refusal = 23

RefusalRenameTarget is a table whose present name is taken while its former one still holds the framework's data (ADR 0180 step 5); its "tables" field names them, and nothing was moved.

const RefusalStatement Refusal = 19

RefusalStatement is a statement the database did not complete.

const RefusalTxClosed Refusal = 20

RefusalTxClosed is a call with the context of a transaction that ended.

const RefusalTxFailed Refusal = 21

RefusalTxFailed is a transaction or a savepoint the database would not open, commit or roll back.

const RefusalUnconfirmed Refusal = 14

RefusalUnconfirmed is a write that stands but whose survival across a power loss is in doubt.

const RefusalUndecodable Refusal = 9

RefusalUndecodable is a record that does not decode into its type.

const RefusalUnencodable Refusal = 10

RefusalUnencodable is an entity that does not encode.

const RefusalUniqueTaken Refusal = 3

RefusalUniqueTaken is another document under a unique index's key.

const RefusalVersionsNotKept Refusal = 15

RefusalVersionsNotKept is a call on the versions of a store that keeps none.

const RefusalVersionsRewrite Refusal = 16

RefusalVersionsRewrite is a rewrite of versions that adds or renumbers one.

const WorkflowCreateEvent string = "create"

WorkflowCreateEvent is the event of a transition Start fires: an entity entering its workflow.

const WorkflowEntityExists WorkflowFailure = 3

WorkflowEntityExists is an entity already under the key Start names.

const WorkflowEntityMissing WorkflowFailure = 2

WorkflowEntityMissing is no entity under the key.

const WorkflowFailureNone WorkflowFailure = 0

WorkflowFailureNone is no failure the framework words.

const WorkflowFunctionPanicked WorkflowFailure = 12

WorkflowFunctionPanicked is a guard or an instant function that panicked.

const WorkflowHookChangedKey WorkflowFailure = 8

WorkflowHookChangedKey is an OnEnter hook that changed its entity's key.

const WorkflowHookChangedState WorkflowFailure = 7

WorkflowHookChangedState is an OnEnter hook that changed the state it entered.

const WorkflowHookFailed WorkflowFailure = 5

WorkflowHookFailed is a hook that returned an error, joined to it; its "hook" and "event" fields name the hook's kind and the event.

const WorkflowHookPanicked WorkflowFailure = 6

WorkflowHookPanicked is a hook that panicked; its "hook", "panic" and "stack" fields say which and how.

const WorkflowJournalFailed WorkflowFailure = 11

WorkflowJournalFailed is the workflow's journal that failed.

const WorkflowKeyEmpty WorkflowFailure = 4

WorkflowKeyEmpty is an entity whose key is empty.

const WorkflowLoopOther WorkflowLoopEvent = 0

WorkflowLoopOther is an event of the loop the framework shows nothing of.

const WorkflowLoopPanicked WorkflowFailure = 13

WorkflowLoopPanicked is the loop that panicked.

const WorkflowLoopRunEnded WorkflowLoopEvent = 2

WorkflowLoopRunEnded is a run ending: Started, Ended, Next and what it could not fire, Err, are set.

const WorkflowLoopRunStarted WorkflowLoopEvent = 1

WorkflowLoopRunStarted is a run starting: Wake and Started are set.

const WorkflowLoopWaiting WorkflowLoopEvent = 3

WorkflowLoopWaiting is the loop asleep until Next, zero for no transition due.

const WorkflowReentrant WorkflowFailure = 9

WorkflowReentrant is an OnEnter hook that fired its own workflow.

const WorkflowStoreFailed WorkflowFailure = 10

WorkflowStoreFailed is the workflow's store that failed.

const WorkflowTransitionRefused WorkflowFailure = 1

WorkflowTransitionRefused is an event that leaves no transition from the entity's state.

const WorkflowTriggerDeadline WorkflowTrigger = 3

WorkflowTriggerDeadline is a timer at an instant the entity carries.

const WorkflowTriggerDelay WorkflowTrigger = 2

WorkflowTriggerDelay is a timer: a duration spent in a state.

const WorkflowTriggerEvent WorkflowTrigger = 1

WorkflowTriggerEvent is an event code fires.

const WorkflowTriggerGuard WorkflowTrigger = 4

WorkflowTriggerGuard is a condition on the entity that holds.

const WorkflowTriggerStart WorkflowTrigger = 0

WorkflowTriggerStart is a creation, which Start fires.

const WorkflowWaitAbandoned WorkflowFailure = 14

WorkflowWaitAbandoned is a caller that stopped waiting for its entity: its context ended.

const WorkflowWakeChange WorkflowWake = 2

WorkflowWakeChange is a write that may have brought one forward.

const WorkflowWakeDue WorkflowWake = 1

WorkflowWakeDue is a transition coming due.

const WorkflowWakeStart WorkflowWake = 0

WorkflowWakeStart is the loop's first run.

const WriteInsert WriteMode = 1

WriteInsert expects nothing under the key, and is refused otherwise.

const WriteReplace WriteMode = 2

WriteReplace expects a document under the key, and is refused otherwise: never a resurrection.

const WriteUpsert WriteMode = 0

WriteUpsert writes whatever the key holds: a creation or a replacement.

Variables

var Jobs atomic.Pointer[JobDriverConfig]

Jobs is the jobs subsystem: the schedules of the framework's jobs and the scheduler that fires them; nil until framework/app/jobs is imported. A product that declares a job without it is refused at the start (ADR 0179 §6).

var Mail atomic.Pointer[MailDriverConfig]

Mail is the mail subsystem: the outbox the framework's mailers keep and the transports that empty it; nil until framework/app/mail is imported. A product that declares a mailer without it is refused at the start (ADR 0179 §6).

var NewHTTPServer atomic.Pointer[func(cfg HTTPConfig) HTTPServer]

NewHTTPServer builds the HTTP engine an app in the server profile serves on; nil until framework/app/server is imported.

var NewStaticFiles atomic.Pointer[func(fsys fs.FS, csp string) (http.Handler, error)]

NewStaticFiles builds the file server of a frontend's tree; nil until framework/app/server is imported.

var OTLP atomic.Pointer[OTLPDriverConfig]

OTLP is the OTLP export subsystem; nil until framework/app/otlp is imported. A product that declares app.OTLP without it is refused at the start (ADR 0179 §6).

var Queues atomic.Pointer[QueueDriverConfig]

Queues is the queue subsystem: the brokers the framework's consumers' queues run on and the migration of a queue's table on a database; nil until framework/app/queue is imported. A product that declares a topic, a subscription, a watch, a queued command or a mailer whose outbox is on a database without it is refused at the start (ADR 0179 §6).

var SampleProcess atomic.Pointer[func() *model.Process]

SampleProcess samples the running process — its heap, goroutines, collections and CPU time — for the runtime graph a serving app answers; nil until framework/app/server is imported, and the graph then carries no process (ADR 0172).

var Stores atomic.Pointer[StoreDriverConfig]

Stores is the store subsystem: the engines the framework's stores run on, the framework's scope on a database and the migrations of the framework's tables; nil until framework/app/store is imported. A product that declares a store or a database without it is refused at the start (ADR 0179 §6).

var Studio atomic.Pointer[StudioDriverConfig]

Studio is the Studio subsystem: the tool's variables and the Studio's routes; nil until framework/app/studio is imported, and the framework then reads none of the tool's variables and serves no route of the Studio.

var Words atomic.Pointer[WordsConfig]

Words is the framework's sentences in the languages after English, the catalogues the Studio shows its reader's language from; nil until framework/app/studio is imported, and the framework then speaks English alone. The terminal, the logs and an error read English whatever a program imports (ADR 0179 Q6).

var Workflows atomic.Pointer[WorkflowDriverConfig]

Workflows is the workflow subsystem: the engine the framework's workflows run on; nil until framework/app/workflow is imported. A product that declares a workflow without it is refused at the start (ADR 0179 §6).

func Refuse

func Refuse(kind Refusal, err error) error

Refuse is err as a refusal of kind.

func Refused

func Refused(err error, kind Refusal) bool

Refused reports whether err, or an error it wraps, is a refusal of kind.

type Broker

Broker is one queue as the framework's core uses it: a publication, the consumer that delivers it, and its dead letters. It grows by the siblings below.

type Broker interface {
	// Consume delivers the queue's messages to cfg's handler until ctx ends
	// or the queue's storage fails.
	Consume(ctx context.Context, cfg ConsumeConfig) error
	// DeadLetters are up to maxLetters of the queue's dead letters, oldest
	// first.
	DeadLetters(ctx context.Context, maxLetters int) ([]DeadLetterValue, error)
	// Publish puts payload in the queue: in the transaction ctx carries for
	// its database, when it lives on one.
	Publish(ctx context.Context, payload []byte) error
}

func (Broker) Consume
func (Broker) Consume(ctx context.Context, cfg ConsumeConfig) error

Consume delivers the queue's messages to cfg's handler until ctx ends or the queue's storage fails.

func (Broker) DeadLetters
func (Broker) DeadLetters(ctx context.Context, maxLetters int) ([]DeadLetterValue, error)

DeadLetters are up to maxLetters of the queue's dead letters, oldest first.

func (Broker) Publish
func (Broker) Publish(ctx context.Context, payload []byte) error

Publish puts payload in the queue: in the transaction ctx carries for its database, when it lives on one.

type Checker

Checker is a Database that says whether it answers. A sibling of Database.

type Checker interface {
	// Check asks the database whether it answers, within its check timeout.
	Check(ctx context.Context) error
}

func (Checker) Check
func (Checker) Check(ctx context.Context) error

Check asks the database whether it answers, within its check timeout.

type Classifier

Classifier is a Database that says whether a failed transaction is one the database asks to run again: a serialization failure, a deadlock, a lock wait that timed out. app.Transact runs such a transaction again, at its outermost level. A sibling of Database.

type Classifier interface {
	// Transient reports whether err asks for the transaction to run again.
	Transient(err error) bool
}

func (Classifier) Transient
func (Classifier) Transient(err error) bool

Transient reports whether err asks for the transaction to run again.

type Clock

Clock is the app's clock as a queue stamps and waits on it: the framework's core hands the one its app runs on, a test's manual clock included.

type Clock interface {
	// After is a channel that receives the clock's instant once d passed.
	After(d time.Duration) <-chan time.Time
	// NewTicker is a ticker that fires every d.
	NewTicker(d time.Duration) Ticker
	// NewTimer is a timer that fires once d passed.
	NewTimer(d time.Duration) Timer
	// Now is the clock's instant.
	Now() time.Time
	// Since is how long ago t was, on the clock.
	Since(t time.Time) time.Duration
	// Sleep waits until d passed.
	Sleep(d time.Duration)
}

func (Clock) After
func (Clock) After(d time.Duration) <-chan time.Time

After is a channel that receives the clock's instant once d passed.

func (Clock) NewTicker
func (Clock) NewTicker(d time.Duration) Ticker

NewTicker is a ticker that fires every d.

func (Clock) NewTimer
func (Clock) NewTimer(d time.Duration) Timer

NewTimer is a timer that fires once d passed.

func (Clock) Now
func (Clock) Now() time.Time

Now is the clock's instant.

func (Clock) Since
func (Clock) Since(t time.Time) time.Duration

Since is how long ago t was, on the clock.

func (Clock) Sleep
func (Clock) Sleep(d time.Duration)

Sleep waits until d passed.

type ConsumeConfig

ConsumeConfig is how a queue's consumer runs: its handler, how long it waits idle, how many messages it handles at once and takes at a time, how it stops, whether it renews a running handler's lease, and when a handler asked to be retried.

type ConsumeConfig struct {
	// Handler handles one delivery: nil acknowledges it, an error has it
	// retried or, through DoNotRetry, dead-lettered at once. Every handler
	// the framework runs tolerates a redelivery.
	Handler       func(ctx context.Context, d DeliveryValue) error
	// PollInterval bounds an idle wait.
	PollInterval  time.Duration
	// Parallelism is how many deliveries are handled at once.
	Parallelism   int
	// BatchSize is how many messages the consumer takes at a time.
	BatchSize     int
	// DrainTimeout is how long the handler running when ctx ends may still
	// run before its context is cancelled; zero cancels it at once.
	DrainTimeout  time.Duration
	// SettleTimeout bounds each outcome sent once ctx ended, and each lease
	// renewal; zero is the queue's own bound.
	SettleTimeout time.Duration
	// AutoExtend renews the lease of the message a handler runs for as long
	// as it runs.
	AutoExtend    bool
	// RetryIn reads, from the error a delivery's handler returned, the delay
	// it asked to be retried after: its queue hands the message back with
	// that delay, the delivery counted. Nil, or false, keeps the queue's own
	// retry delay.
	RetryIn       func(err error) (delay time.Duration, asked bool)
}

type Database

Database is the framework's scope on one database (ADR 0179 §2): the transactions app.Transact opens on it, their savepoints, and the functions held until their end. The core knows a database only through it; the store package implements it over the SDK's sql. It grows by the siblings below.

type Database interface {
	// Defer holds fn until the transaction ctx carries for the database
	// commits, and reports true; outside one it holds nothing and reports
	// false.
	Defer(ctx context.Context, fn func()) bool
	// InTransaction reports whether ctx carries a transaction of this
	// database.
	InTransaction(ctx context.Context) bool
	// OnAbort holds fn until the work of the scope ctx carries for the
	// database is undone, and reports true; outside one it holds nothing
	// and reports false.
	OnAbort(ctx context.Context, fn func(ctx context.Context)) bool
	// Transact runs fn in a transaction of the database, or in a savepoint
	// of the one ctx carries for it: nil commits or releases, an error
	// rolls back. opts are the transaction's: its isolation level and
	// whether it only reads; a savepoint is given none.
	Transact(ctx context.Context, opts TxOptionsValue, fn func(ctx context.Context) error) error
}

func (Database) Defer
func (Database) Defer(ctx context.Context, fn func()) bool

Defer holds fn until the transaction ctx carries for the database commits, and reports true; outside one it holds nothing and reports false.

func (Database) InTransaction
func (Database) InTransaction(ctx context.Context) bool

InTransaction reports whether ctx carries a transaction of this database.

func (Database) OnAbort
func (Database) OnAbort(ctx context.Context, fn func(ctx context.Context)) bool

OnAbort holds fn until the work of the scope ctx carries for the database is undone, and reports true; outside one it holds nothing and reports false.

func (Database) Transact
func (Database) Transact(ctx context.Context, opts TxOptionsValue, fn func(ctx context.Context) error) error

Transact runs fn in a transaction of the database, or in a savepoint of the one ctx carries for it: nil commits or releases, an error rolls back. opts are the transaction's: its isolation level and whether it only reads; a savepoint is given none.

type DatabaseConfig

DatabaseConfig is one database a product declares, as the framework opened it: its pool, its dialect, its tuning and the timeout of each call.

type DatabaseConfig struct {
	// Name is the database's, as the product declared it.
	Name         string
	// DB is the pool app.Engine opened.
	DB           *sql.DB
	// Dialect is the engine's SQL dialect: "postgres", "mysql" or
	// "sqlite".
	Dialect      string
	// Timeout bounds each call the framework makes on the database.
	Timeout      time.Duration
	// MaxOpen and MaxIdle bound the pool's connections.
	MaxOpen      int
	// MaxOpen and MaxIdle bound the pool's connections.
	MaxIdle      int
	// MaxLifetime and MaxIdleTime bound a connection's life.
	MaxLifetime  time.Duration
	// MaxLifetime and MaxIdleTime bound a connection's life.
	MaxIdleTime  time.Duration
	// CheckTimeout bounds a check of the database.
	CheckTimeout time.Duration
	// Transient is the engine's own reading of a failed transaction — true
	// when the database asks for it to run again —, nil when the engine
	// offers none (app.Classifier). The store subsystem reads the SDK's
	// Classify beside it.
	Transient    func(err error) bool
}

type DeadLetterManager

DeadLetterManager is a Broker whose dead letters an operator replays into the live queue or drops for good, from the product's CLI (issue #1138). A sibling of Broker.

type DeadLetterManager interface {
	// Drop deletes the dead letter id for good. found is false when the
	// queue holds no dead letter id.
	Drop(ctx context.Context, id string) (found bool, err error)
	// Replay moves the dead letter id back into the live queue, its
	// attempts counted afresh: its consumer handles it again. found is
	// false when the queue holds no dead letter id.
	Replay(ctx context.Context, id string) (found bool, err error)
}

func (DeadLetterManager) Drop
func (DeadLetterManager) Drop(ctx context.Context, id string) (found bool, err error)

Drop deletes the dead letter id for good. found is false when the queue holds no dead letter id.

func (DeadLetterManager) Replay
func (DeadLetterManager) Replay(ctx context.Context, id string) (found bool, err error)

Replay moves the dead letter id back into the live queue, its attempts counted afresh: its consumer handles it again. found is false when the queue holds no dead letter id.

type DeadLetterValue

DeadLetterValue is a message its queue gave up on: when, why, and how many times it was delivered.

type DeadLetterValue struct {
	// FailedAt is when its last attempt failed.
	FailedAt   time.Time
	// Reason is the failure's identifier.
	Reason     string
	// Cause is the failure's public text, "" for none.
	Cause      string
	// Message is the message, unmodified.
	Message    MessageValue
	// Trail is the codes the failure gathered as it was wrapped, oldest
	// first, nil for none.
	Trail      []uint32
	// Code is the failure's error code, 0 for none.
	Code       uint32
	// Deliveries counts its deliveries.
	Deliveries int
}

type DeliveryValue

DeliveryValue is one delivery of a message: the message, and how many times it has been delivered, this one included.

type DeliveryValue struct {
	// Message is what is delivered.
	Message    MessageValue
	// Deliveries counts the deliveries, this one included.
	Deliveries int
}

type DocumentSink

DocumentSink is a store's documents on the database a data copy writes. A sibling of Documents.

type DocumentSink interface {
	// InsertRaw writes a document of a store that keeps no versions, as it
	// rests.
	InsertRaw(ctx context.Context, raw json.RawMessage) error
	// PutDocument writes the document key with its versions and its trash
	// as they are given.
	PutDocument(ctx context.Context, key string, versions []VersionValue, trashedAt time.Time) error
}

func (DocumentSink) InsertRaw
func (DocumentSink) InsertRaw(ctx context.Context, raw json.RawMessage) error

InsertRaw writes a document of a store that keeps no versions, as it rests.

func (DocumentSink) PutDocument
func (DocumentSink) PutDocument(ctx context.Context, key string, versions []VersionValue, trashedAt time.Time) error

PutDocument writes the document key with its versions and its trash as they are given.

type DocumentSource

DocumentSource is an engine that says the document store it runs on: itself, or the one what it wraps runs on. A data copy reads and writes a store through it (ADR 0178 C7). A sibling of StoreEngine.

type DocumentSource interface {
	// Documents is the document store the engine runs on, and whether there
	// is one.
	Documents() (Documents, bool)
}

func (DocumentSource) Documents
func (DocumentSource) Documents() (Documents, bool)

Documents is the document store the engine runs on, and whether there is one.

type DocumentValue

DocumentValue is a record as a store's engine holds it (ADR 0179 §2): its JSON as it rests, byte for byte what the framework encodes, and the entity once decoded, kept beside it so that a read, an index or a privacy walk does not decode it twice.

type DocumentValue struct {
	// JSON is the record as it rests.
	JSON  json.RawMessage
	// Value is the entity decoded from JSON, nil until something decoded it;
	// the store's typed facade asserts it to its type.
	Value any
}

type Documents

Documents is a store's documents as they rest, as a data copy reads them.

type Documents interface {
	// Current is the document key as the store keeps it.
	Current(ctx context.Context, key string) (json.RawMessage, error)
	// KeepsVersions reports whether the store keeps versions.
	KeepsVersions() bool
	// KeyList yields every key the store holds, in key order.
	KeyList(ctx context.Context) iter.Seq2[string, error]
	// TombstoneList is the trash, in key order: none when the store keeps
	// no versions.
	TombstoneList(ctx context.Context) ([]TombstoneValue, error)
	// VersionList is the versions of the document key, newest first.
	VersionList(ctx context.Context, key string) ([]VersionValue, error)
}

func (Documents) Current
func (Documents) Current(ctx context.Context, key string) (json.RawMessage, error)

Current is the document key as the store keeps it.

func (Documents) KeepsVersions
func (Documents) KeepsVersions() bool

KeepsVersions reports whether the store keeps versions.

func (Documents) KeyList
func (Documents) KeyList(ctx context.Context) iter.Seq2[string, error]

KeyList yields every key the store holds, in key order.

func (Documents) TombstoneList
func (Documents) TombstoneList(ctx context.Context) ([]TombstoneValue, error)

TombstoneList is the trash, in key order: none when the store keeps no versions.

func (Documents) VersionList
func (Documents) VersionList(ctx context.Context, key string) ([]VersionValue, error)

VersionList is the versions of the document key, newest first.

type EnterHookSpec

EnterHookSpec is one hook run as an entity enters a state, before it is stored: an error cancels the transition.

type EnterHookSpec struct {
	// Fn runs the hook; it may change the entity, not its state nor its
	// key.
	Fn    func(ctx context.Context, e *WorkflowEntityValue) error
	// State is the state whose entering runs it.
	State string
}

type EntrySource

EntrySource is an engine that lists its records as they rest with their keys: what a sealing store reads its records by. A sibling of StoreEngine.

type EntrySource interface {
	// KeyedEntries returns up to limit records as they rest, in key order.
	KeyedEntries(ctx context.Context, limit int) ([]EntryValue, error)
}

func (EntrySource) KeyedEntries
func (EntrySource) KeyedEntries(ctx context.Context, limit int) ([]EntryValue, error)

KeyedEntries returns up to limit records as they rest, in key order.

type EntryValue

EntryValue is a record as it rests, with its key: what an engine lists for a reader that cannot key a record itself.

type EntryValue struct {
	// Key is the record's key.
	Key  string
	// JSON is the record as it rests.
	JSON json.RawMessage
}

type Executor

Executor is what a migration's step runs its statements on: the transaction its migration runs in.

type Executor interface {
	// ExecContext runs a statement that returns no rows.
	ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error)
	// QueryContext runs a query that returns rows.
	QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error)
	// QueryRowContext runs a query that returns at most one row.
	QueryRowContext(ctx context.Context, query string, args ...any) *sql.Row
}

func (Executor) ExecContext
func (Executor) ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error)

ExecContext runs a statement that returns no rows.

func (Executor) QueryContext
func (Executor) QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error)

QueryContext runs a query that returns rows.

func (Executor) QueryRowContext
func (Executor) QueryRowContext(ctx context.Context, query string, args ...any) *sql.Row

QueryRowContext runs a query that returns at most one row.

type Folder

Folder is an engine that keeps what its writes left beside its data, and can fold it in now. A sibling of StoreEngine.

type Folder interface {
	// Fold rewrites the store's data with only what it holds now.
	Fold(ctx context.Context) error
}

func (Folder) Fold
func (Folder) Fold(ctx context.Context) error

Fold rewrites the store's data with only what it holds now.

type HTTPConfig

HTTPConfig is what the framework asks of the HTTP engine: where to listen, its one socket, its bounds, and the handler.

type HTTPConfig struct {
	// Addr is where to listen, "host:port".
	Addr           string
	// Shards is how many sockets the engine opens on Addr.
	Shards         int
	// ReadHeader, Read, Write and Idle bound a request's phases.
	ReadHeader     time.Duration
	// ReadHeader, Read, Write and Idle bound a request's phases.
	Read           time.Duration
	// ReadHeader, Read, Write and Idle bound a request's phases.
	Write          time.Duration
	// ReadHeader, Read, Write and Idle bound a request's phases.
	Idle           time.Duration
	// MaxHeaderBytes bounds a request's header.
	MaxHeaderBytes int
	// Handler answers every request.
	Handler        http.Handler
}

type HTTPServer

HTTPServer is the HTTP engine the framework starts, reads and stops.

type HTTPServer interface {
	// Shutdown drains the engine within ctx.
	Shutdown(ctx context.Context) error
	// Start binds the address and serves, returning once bound.
	Start(ctx context.Context) error
	// State says what the engine binds and serves.
	State() HTTPState
}

func (HTTPServer) Shutdown
func (HTTPServer) Shutdown(ctx context.Context) error

Shutdown drains the engine within ctx.

func (HTTPServer) Start
func (HTTPServer) Start(ctx context.Context) error

Start binds the address and serves, returning once bound.

func (HTTPServer) State
func (HTTPServer) State() HTTPState

State says what the engine binds and serves.

type HTTPState

HTTPState is what the HTTP engine says of itself once it runs: the address it bound, and its connections.

type HTTPState struct {
	// Addr is the address the engine bound, "" before it did.
	Addr      string
	// Listeners is how many sockets it listens on.
	Listeners int
	// Active are the connections being served, Total those accepted since
	// the start, Rejected those refused.
	Active    int64
	Total     uint64
	Rejected  uint64
}

type IndexSpec

IndexSpec declares one secondary index of a store, over documents: the product's index function on its type, wrapped once at the declaration.

type IndexSpec struct {
	// Name reads the index, and names it in a refusal.
	Name   string
	// Unique refuses a write that would file two documents under one key.
	Unique bool
	// Keys are a document's keys in the index; an empty key is not indexed.
	Keys   func(d DocumentValue) []string
}

type JobDriverConfig

JobDriverConfig is what framework/app/jobs plugs into kit: how a job's schedule is read from its declaration, and how the scheduler that fires the app's jobs opens.

type JobDriverConfig struct {
	// Every is the schedule of a job that runs every period, first one
	// period after the scheduler starts; a period that is not positive is
	// refused.
	Every func(period time.Duration) (JobScheduleFunc, error)
	// Cron is the schedule of a five-field POSIX cron expression, in the
	// process's local time zone; an expression it cannot read is refused.
	Cron  func(expr string) (JobScheduleFunc, error)
	// Open opens the scheduler the app's jobs run on, as cfg says, with no
	// entry yet.
	Open  func(cfg *JobSchedulerConfig) JobScheduler
}

type JobEntryValue

JobEntryValue is one job as the scheduler fires it: its name, its schedule, and the run.

type JobEntryValue struct {
	// Name names the job; the scheduler refuses a name it holds already.
	Name             string
	// Schedule says when the job runs next.
	Schedule         JobScheduleFunc
	// Run runs the job once; its error is the result's.
	Run              func(ctx context.Context) error
	// Overlap is what a fire does while the job's previous run goes, as the
	// SDK scheduler's OverlapPolicy numbers it: 0 skips it — the zero —, 1
	// runs it beside, 2 replaces the run; the scheduler refuses any other.
	Overlap          uint8
	// StartingDeadline bounds how late a fire may still start; zero is no
	// bound.
	StartingDeadline time.Duration
}

type JobResultValue

JobResultValue is one decision of the scheduler: a run of a job, or a fire it skipped.

type JobResultValue struct {
	// Name is the job's.
	Name      string
	// Scheduled is the instant the fire was due.
	Scheduled time.Time
	// Started and Finished bound the run; zero for a fire that did not run.
	Started   time.Time
	// Started and Finished bound the run; zero for a fire that did not run.
	Finished  time.Time
	// Missed counts the fires that came due while the scheduler could not
	// fire them, skipped rather than caught up.
	Missed    int
	// Skipped says the fire did not run: a run of the same job was going.
	Skipped   bool
	// Expired says the fire did not run: the scheduler came to it more
	// than the job's starting deadline after its instant.
	Expired   bool
	// Replaced says a newer fire of a job that replaces its runs cancelled
	// this one — before it started when Started is zero.
	Replaced  bool
	// Err is the run's error.
	Err       error
}

type JobScheduleFunc

JobScheduleFunc says when a job runs next after an instant: the instant, and false when it never runs again.

type JobScheduleFunc func(after time.Time) (next time.Time, ok bool)

type JobScheduler

JobScheduler fires the app's jobs, each on its schedule, on the app's clock: a fire due while the previous run of the same job is going is skipped, a missed one is counted, never caught up.

type JobScheduler interface {
	// Add registers a job; it is refused while the scheduler runs, for a
	// name it holds already, and for an entry with no name, run or
	// schedule.
	Add(entry JobEntryValue) error
	// Run fires the jobs until ctx ends, then waits for the runs going.
	Run(ctx context.Context) error
}

func (JobScheduler) Add
func (JobScheduler) Add(entry JobEntryValue) error

Add registers a job; it is refused while the scheduler runs, for a name it holds already, and for an entry with no name, run or schedule.

func (JobScheduler) Run
func (JobScheduler) Run(ctx context.Context) error

Run fires the jobs until ctx ends, then waits for the runs going.

type JobSchedulerConfig

JobSchedulerConfig is the scheduler the app's jobs run on: the app's clock and what the framework hears of each fire.

type JobSchedulerConfig struct {
	// Clock is the app's clock, which the scheduler stamps and waits on.
	Clock    Clock
	// OnResult hears every decision of the scheduler — each run, with the
	// job's own error, and each fire skipped or missed —, one at a time.
	OnResult func(res JobResultValue)
}

type Keyser

Keyser is an engine that lists the keys of its documents, in key order, above after, without reading a document. A sibling of StoreEngine.

type Keyser interface {
	// Keys yields the keys above after, in order, then its failure if any.
	Keys(ctx context.Context, after string) iter.Seq2[string, error]
}

func (Keyser) Keys
func (Keyser) Keys(ctx context.Context, after string) iter.Seq2[string, error]

Keys yields the keys above after, in order, then its failure if any.

type LaterPublisher

LaterPublisher is a Broker that publishes a message for later, and once per key. A sibling of Broker.

type LaterPublisher interface {
	// PublishAt puts payload in the queue, received by no consumer before
	// at: in the transaction ctx carries for its database, when it lives on
	// one.
	PublishAt(ctx context.Context, payload []byte, at time.Time) error
	// PublishOnce puts payload in the queue unless a publication under key
	// was made within window, and reports whether it did.
	PublishOnce(ctx context.Context, key string, payload []byte, window time.Duration) (published bool, err error)
}

func (LaterPublisher) PublishAt
func (LaterPublisher) PublishAt(ctx context.Context, payload []byte, at time.Time) error

PublishAt puts payload in the queue, received by no consumer before at: in the transaction ctx carries for its database, when it lives on one.

func (LaterPublisher) PublishOnce
func (LaterPublisher) PublishOnce(ctx context.Context, key string, payload []byte, window time.Duration) (published bool, err error)

PublishOnce puts payload in the queue unless a publication under key was made within window, and reports whether it did.

type LiveMessageValue

LiveMessageValue is a message waiting in its queue, as it lies: when it is next visible, how many times it was delivered, and whether a consumer holds it.

type LiveMessageValue struct {
	// VisibleAt is when the message is next delivered.
	VisibleAt  time.Time
	// Message is the message.
	Message    MessageValue
	// Deliveries counts its deliveries so far.
	Deliveries int
	// Leased reports whether a consumer holds it.
	Leased     bool
}

type MailAttemptValue

MailAttemptValue is one delivery attempt of a mail: its outbox ID, its number, when the mail was queued, and what the spool kept of its Send.

type MailAttemptValue struct {
	// QueuedAt is when the mail was put in the outbox.
	QueuedAt time.Time
	// Meta is what Annotate kept of the Send.
	Meta     map[string]string
	// ID is the mail's outbox ID.
	ID       string
	// Attempt numbers the attempt, from 1.
	Attempt  int
}

type MailCaptureSource

MailCaptureSource is a transport that keeps what it composed: the capture transport, whose last message the Studio's mailbox shows. A sibling of MailSink.

type MailCaptureSource interface {
	// Composed is the last message the transport composed, nil for none.
	Composed() []byte
}

func (MailCaptureSource) Composed
func (MailCaptureSource) Composed() []byte

Composed is the last message the transport composed, nil for none.

type MailDeadLetterValue

MailDeadLetterValue is a mail an outbox gave up on, read back from its dead letters: what the mailbox of a later run shows of it, why it was given up included.

type MailDeadLetterValue struct {
	// Meta is what Annotate kept of the Send.
	Meta     map[string]string
	// FailedAt is when its last attempt failed.
	FailedAt time.Time
	// QueuedAt is when the mail was put in the outbox.
	QueuedAt time.Time
	// Message is the mail.
	Message  MailValue
	// ID is the mail's outbox ID; empty when its record did not decode, and
	// QueueID then names it.
	ID       string
	// QueueID is the outbox queue's identifier for its record.
	QueueID  string
	// Cause is its last failure's public text, "" for none.
	Cause    string
	// Attempts counts its delivery attempts.
	Attempts int
	// GivenUp is why it was given up, read from its last failure's code and
	// trail as the outbox kept them.
	GivenUp  MailGiveUp
}

type MailDriverConfig

MailDriverConfig is what framework/app/mail plugs into kit: how a mailer's outbox opens, the SDK's verdict on a mail, the transports a mailer hands its mail to, and how the framework tells the spool's refusals apart.

type MailDriverConfig struct {
	// Open opens one mailer's outbox as cfg says, closed until it runs.
	Open      func(cfg *MailSpoolConfig) (MailSpool, error)
	// Validate is the SDK's verdict on a mail: nil when the outbox takes it,
	// else what is wrong with it, in the SDK's public words.
	Validate  func(msg MailValue) error
	// Capture is a transport that delivers nothing and keeps the last
	// message it composed (MailCaptureSource).
	Capture   func() MailSink
	// ParseSMTP reads an SMTP URL — smtp://user:password@host:port?tls=
	// starttls|implicit|none, smtps:// for implicit TLS — as the SDK's
	// SMTP transport would take it.
	ParseSMTP func(url string) (MailRelayValue, error)
	// NewSMTP is the SDK's SMTP transport to relay, which dials nothing
	// until a mail is sent.
	NewSMTP   func(relay *MailRelayValue) (MailSink, error)
	// Refused reports whether err, or an error it wraps, is the spool's or
	// the URL's refusal of kind: the SDK's sentinels stay in the subsystem,
	// and the error keeps the fields the SDK gave it.
	Refused   func(err error, kind MailRefusal) bool
}

type MailEvent

MailEvent is what a spool reports of a mail.

type MailEvent uint8

type MailEventValue

MailEventValue is what a spool reports of a mail: its kind, the mail and its outbox ID, the attempt, when, the failure of a failed attempt, and why a dead letter was given up.

type MailEventValue struct {
	// Err is a failed attempt's failure.
	Err      error
	// Reply is the SMTP reply the failure carries, nil for none: the
	// receiving server's own words, never shown in a public message.
	Reply    *textproto.Error
	// Meta is what Annotate kept of the Send.
	Meta     map[string]string
	// At is when the event happened.
	At       time.Time
	// QueuedAt is when the mail was put in the outbox.
	QueuedAt time.Time
	// Message is the mail.
	Message  MailValue
	// ID is the mail's outbox ID.
	ID       string
	// Attempt numbers the attempt the event is about.
	Attempt  int
	// Kind is what happened.
	Kind     MailEvent
	// GivenUp is why a dead letter was given up, for MailEventDeadLettered.
	GivenUp  MailGiveUp
}

type MailGiveUp

MailGiveUp is why a spool gave a mail up.

type MailGiveUp uint8

type MailRefusal

MailRefusal is a refusal of the mail subsystem, as the framework words it.

type MailRefusal uint8

type MailRelayValue

MailRelayValue is an SMTP relay as the SDK's transport takes it: its configuration, which holds the password and is handed to NewSMTP and never kept or printed, and what may be shown of it.

type MailRelayValue struct {
	// Config is the SDK's SMTP configuration, held as any.
	Config any
	// Server is where it delivers, host:port.
	Server string
	// TLS is its TLS mode as the URL spells it: starttls, implicit or none.
	TLS    string
}

type MailSink

MailSink is what a mailer hands a mail to: the SDK's SMTP transport, or its capture transport, which delivers nothing. It grows by the sibling below.

type MailSink interface {
	// Send delivers msg.
	Send(ctx context.Context, msg MailValue) error
}

func (MailSink) Send
func (MailSink) Send(ctx context.Context, msg MailValue) error

Send delivers msg.

type MailSpool

MailSpool is one mailer's outbox as the framework's core uses it: a mail put in it at once or under an ID the framework minted, the loop that hands each mail to the transport, and its dead letters.

type MailSpool interface {
	// Close releases the outbox.
	Close() error
	// DeadLetters returns up to maxLetters of the mails earlier runs gave up
	// on, oldest first, each with why.
	DeadLetters(ctx context.Context, maxLetters int) ([]MailDeadLetterValue, error)
	// Run hands each mail to the transport until ctx ends.
	Run(ctx context.Context) error
	// Send puts msg in the outbox — in the transaction ctx carries for its
	// database, when it lives on one — and returns its outbox ID.
	Send(ctx context.Context, msg MailValue) (string, error)
	// SendWithID puts msg in the outbox under id, minted by the framework.
	SendWithID(ctx context.Context, id string, msg MailValue) error
}

func (MailSpool) Close
func (MailSpool) Close() error

Close releases the outbox.

func (MailSpool) DeadLetters
func (MailSpool) DeadLetters(ctx context.Context, maxLetters int) ([]MailDeadLetterValue, error)

DeadLetters returns up to maxLetters of the mails earlier runs gave up on, oldest first, each with why.

func (MailSpool) Run
func (MailSpool) Run(ctx context.Context) error

Run hands each mail to the transport until ctx ends.

func (MailSpool) Send
func (MailSpool) Send(ctx context.Context, msg MailValue) (string, error)

Send puts msg in the outbox — in the transaction ctx carries for its database, when it lives on one — and returns its outbox ID.

func (MailSpool) SendWithID
func (MailSpool) SendWithID(ctx context.Context, id string, msg MailValue) error

SendWithID puts msg in the outbox under id, minted by the framework.

type MailSpoolConfig

MailSpoolConfig is one mailer's outbox: the transport each attempt runs, the app's clock, what the framework hears of its mails, its retries, and where it keeps them — a queue on the database that keeps the mailer's service, a directory, or memory.

type MailSpoolConfig struct {
	// Transport makes one delivery attempt of msg; the spool retries a
	// failure, or dead-letters the mail after its last attempt.
	Transport       func(ctx context.Context, msg MailValue, attempt MailAttemptValue) error
	// Clock is the app's clock, which the spool stamps and waits on.
	Clock           Clock
	// Observe is told each event of each mail.
	Observe         func(e *MailEventValue)
	// Annotate is what the spool keeps of a Send for its deliveries, read
	// from the Send's context.
	Annotate        func(ctx context.Context) map[string]string
	// NewID mints a mail's outbox ID.
	NewID           func() (string, error)
	// Outbox is the queue the spool keeps its mails in on a database —
	// the queue subsystem's, sealed —, nil for a directory or memory.
	Outbox          Broker
	// Database is the database Outbox is on, whose transaction a mail sent
	// in one joins; nil for none.
	Database        Database
	// From is the sender of every mail that names none: the SDK's
	// mail.Address, held as any.
	From            MailValue
	// Dir is the directory the spool keeps its own queue in; with no Outbox
	// and no Dir, the outbox is in memory.
	Dir             string
	// BackoffBase is the wait after a failed attempt, doubled after each,
	// up to BackoffMax.
	BackoffBase     time.Duration
	// BackoffMax bounds the wait after a failed attempt.
	BackoffMax      time.Duration
	// SendTimeout bounds one attempt.
	SendTimeout     time.Duration
	// PollInterval bounds an idle wait.
	PollInterval    time.Duration
	// MaxAttempts is how many attempts a mail gets before it is
	// dead-lettered.
	MaxAttempts     int
	// MaxMessageBytes bounds one mail in the spool's own queue; zero is the
	// spool's own bound.
	MaxMessageBytes int
	// MaxAge is how long after it was queued a mail may still be retried:
	// an attempt that fails later gives it up; zero sets no age.
	MaxAge          time.Duration
	// RetryPermanent retries a mail the receiving server refused for good —
	// an SMTP 5xx reply — like a temporary failure, instead of giving it up
	// at once.
	RetryPermanent  bool
}

type MailValue

MailValue is a value of the SDK's mail package as it crosses the contract: a mail.Message, or a sender's mail.Address, held as any — the framework's core names the SDK's mail types, plug names none.

type MailValue struct {
	// Value is the SDK's mail value.
	Value any
}

type MessageMover

MessageMover is a Broker whose messages a data copy reads and writes as they lie, without a lease, with their counts and their instants. A sibling of Broker.

type MessageMover interface {
	// Messages are up to maxMessages live messages after the identifier
	// after, "" for the first, in their queue's order.
	Messages(ctx context.Context, after string, maxMessages int) ([]LiveMessageValue, error)
	// PutDeadLetter writes dead, with its cause, under an identifier of the
	// queue's own, and returns it.
	PutDeadLetter(ctx context.Context, dead DeadLetterValue) (string, error)
	// PutMessage writes live under an identifier of the queue's own, and
	// returns it.
	PutMessage(ctx context.Context, live LiveMessageValue) (string, error)
}

func (MessageMover) Messages
func (MessageMover) Messages(ctx context.Context, after string, maxMessages int) ([]LiveMessageValue, error)

Messages are up to maxMessages live messages after the identifier after, "" for the first, in their queue's order.

func (MessageMover) PutDeadLetter
func (MessageMover) PutDeadLetter(ctx context.Context, dead DeadLetterValue) (string, error)

PutDeadLetter writes dead, with its cause, under an identifier of the queue's own, and returns it.

func (MessageMover) PutMessage
func (MessageMover) PutMessage(ctx context.Context, live LiveMessageValue) (string, error)

PutMessage writes live under an identifier of the queue's own, and returns it.

type MessageValue

MessageValue is one message of a queue: its identifier, its payload as the framework encoded it, and when it was published.

type MessageValue struct {
	// EnqueuedAt is when the message was published.
	EnqueuedAt time.Time
	// ID identifies the message in its queue.
	ID         string
	// Payload is the message as the framework encoded it.
	Payload    []byte
}

type MigrationValue

MigrationValue is one versioned change of a database's schema and its reversal, as the core hands it to the store subsystem: a product's app.Migration, or one of the framework's own, its steps on the standard library's types.

type MigrationValue struct {
	// Version orders the migration in its set: non-zero and unique.
	Version uint64
	// Name labels it in the version table.
	Name    string
	// Up applies the change.
	Up      Step
	// Down reverses it.
	Down    Step
}

type Migrator

Migrator is one set of migrations on a database.

type Migrator interface {
	// Down reverses the applied migrations above version, newest first.
	Down(ctx context.Context, version uint64) error
	// Plan is the set's pending migrations, oldest first, applying nothing.
	Plan(ctx context.Context) ([]MigrationValue, error)
	// Up applies every pending migration, in order.
	Up(ctx context.Context) error
}

func (Migrator) Down
func (Migrator) Down(ctx context.Context, version uint64) error

Down reverses the applied migrations above version, newest first.

func (Migrator) Plan
func (Migrator) Plan(ctx context.Context) ([]MigrationValue, error)

Plan is the set's pending migrations, oldest first, applying nothing.

func (Migrator) Up
func (Migrator) Up(ctx context.Context) error

Up applies every pending migration, in order.

type MigratorProvider

MigratorProvider is a Database that runs a set of migrations under a version table of its own, and so a lock of its own. A sibling of Database.

type MigratorProvider interface {
	// Migrator is the set ms, under the version table table.
	Migrator(table string, ms []MigrationValue) (Migrator, error)
}

func (MigratorProvider) Migrator
func (MigratorProvider) Migrator(table string, ms []MigrationValue) (Migrator, error)

Migrator is the set ms, under the version table table.

type OTLPBatchValue

OTLPBatchValue is one batch as the product's own sender receives it: its signal and its OTLP/JSON document, posted to a collector as it is.

type OTLPBatchValue struct {
	// Signal is OTLPTraces or OTLPMetrics.
	Signal   string
	// Document is the OTLP/JSON export request.
	Document []byte
}

type OTLPConfig

OTLPConfig is what the framework asks of an export: who produces the telemetry, where it goes, where it waits, its bounds and the app's clock.

type OTLPConfig struct {
	// Clock is the app's clock: the queues stamp and age a batch on it, the
	// retries and each attempt's bound wait on it, the metrics are
	// collected on it.
	Clock         Clock
	// Headers ride on every request to the collector — an Authorization, a
	// tenant —; they are the secret otlp-headers, never shown.
	Headers       map[string]string
	// Send, when set, ships a batch in place of the OTLP/HTTP exporters:
	// the product's own sender. Retryable then classifies its failures.
	Send          func(ctx context.Context, batch OTLPBatchValue) error
	// Retryable classifies a failure of Send: a later attempt may cure it.
	// Unused without Send: the OTLP/HTTP exporters classify their own.
	Retryable     func(err error) bool
	// OnError hears what the export could not keep — a batch of spans or a
	// snapshot its queue refused — and what it could not close; the core
	// logs it. The forwarder counts every batch it loses on its own.
	OnError       func(err error)
	// Service and Version name the producer: the resource's service.name
	// and the instrumentation scope's version.
	Service       string
	// Service and Version name the producer: the resource's service.name
	// and the instrumentation scope's version.
	Version       string
	// Endpoint is the collector's base URL, "http://collector:4318": each
	// signal's path is appended to it. Unused with Send.
	Endpoint      string
	// Dir is the directory the two queues lie in, one subdirectory per
	// signal; "" keeps them in memory, lost at a stop. Unused with Database.
	Dir           string
	// Database keeps the two queues, one table each (Tables), nil when Dir
	// or memory does: a scope the store subsystem's Database opened, on
	// which the queue subsystem opens the SDK's SQL broker (OpenSDK).
	Database      Database
	// Tables are the queues' tables on Database, by signal.
	Tables        map[string]string
	// WhenFull is what a full queue does with a new batch: OTLPDropOldest,
	// OTLPDropNewest or OTLPBlock.
	WhenFull      string
	// MaxBytes bounds the bytes each queue holds.
	MaxBytes      int64
	// MaxBatches bounds the batches each queue holds.
	MaxBatches    int
	// MaxAge is how long after it was queued a batch may still be sent.
	MaxAge        time.Duration
	// SendTimeout bounds one attempt, and the hand-over of the spans the
	// batch sink exports to their queue.
	SendTimeout   time.Duration
	// Interval is how often the metrics are collected and queued.
	Interval      time.Duration
	// DrainTimeout is how long the batch being sent at a stop may still
	// run; SettleTimeout bounds each acknowledgement once the stop began,
	// and the flush of what the export still holds in memory.
	DrainTimeout  time.Duration
	// DrainTimeout is how long the batch being sent at a stop may still
	// run; SettleTimeout bounds each acknowledgement once the stop began,
	// and the flush of what the export still holds in memory.
	SettleTimeout time.Duration
}

type OTLPDeadLetterValue

OTLPDeadLetterValue is one batch a signal's queue gave up on — the collector refused it for good —, as the product's CLI lists it: never its payload.

type OTLPDeadLetterValue struct {
	// FailedAt is when its last attempt failed.
	FailedAt   time.Time
	// ID identifies it in its queue: what replay and drop take.
	ID         string
	// Reason is the failure's identifier.
	Reason     string
	// Cause is the failure's public text, "" for none.
	Cause      string
	// Trail is the codes the failure gathered as it was wrapped, oldest
	// first, nil for none.
	Trail      []uint32
	// Code is the failure's error code, 0 for none.
	Code       uint32
	// Deliveries counts its attempts.
	Deliveries int
	// Size is its payload's bytes.
	Size       int
}

type OTLPDriverConfig

OTLPDriverConfig is what framework/app/otlp plugs into the framework: how an app's export opens.

type OTLPDriverConfig struct {
	// Open opens the export cfg describes: its two queues — read, the
	// backlog a previous process left counted —, its senders and its
	// meter. It sends nothing until OTLPExporter.Run.
	Open   func(ctx context.Context, cfg *OTLPConfig) (OTLPExporter, error)
	// Queue opens one signal's queue as Open keeps it — the same directory
	// or table, the same policy — for the product's CLI, which lists and
	// replays its dead letters (issue #536); it is refused when the queue
	// would be in memory, where no dead letter outlives its process.
	Queue  func(ctx context.Context, cfg *OTLPConfig, signal string) (OTLPQueue, error)
	// Policy is the policy Open and Queue open each signal's queue under
	// for cfg — its lease, its deliveries, its largest message —, for
	// the product's CLI, which opens the same queues through the queue
	// subsystem to move them onto a database (otlp migrate, issue #586).
	Policy func(cfg *OTLPConfig) QueuePolicyValue
}

type OTLPExporter

OTLPExporter is an app's export, open: where the tracer hands its spans, what the framework records of each unit of work, the loop that sends, and what it counts.

type OTLPExporter interface {
	// Meter is the product's own meter, collected at each interval beside
	// the framework's, into the same metrics queue, under the same resource
	// and a scope named after the product.
	Meter() OTLPMeterValue
	// Record counts one unit of work the framework observed on node: its
	// operation, how long it took, and whether it failed.
	Record(node string, op string, took time.Duration, failed bool)
	// Run sends the queued batches and collects the metrics until ctx ends;
	// then it flushes what it holds in memory into the queues, lets the
	// batch being sent finish within the drain, and closes the queues.
	Run(ctx context.Context) error
	// SpanSink is the sink the app's tracer ends its spans into.
	SpanSink() OTLPSinkValue
	// Stats is what each signal's queue holds, has sent and has lost.
	Stats() []OTLPStatsValue
}

func (OTLPExporter) Meter
func (OTLPExporter) Meter() OTLPMeterValue

Meter is the product's own meter, collected at each interval beside the framework's, into the same metrics queue, under the same resource and a scope named after the product.

func (OTLPExporter) Record
func (OTLPExporter) Record(node string, op string, took time.Duration, failed bool)

Record counts one unit of work the framework observed on node: its operation, how long it took, and whether it failed.

func (OTLPExporter) Run
func (OTLPExporter) Run(ctx context.Context) error

Run sends the queued batches and collects the metrics until ctx ends; then it flushes what it holds in memory into the queues, lets the batch being sent finish within the drain, and closes the queues.

func (OTLPExporter) SpanSink
func (OTLPExporter) SpanSink() OTLPSinkValue

SpanSink is the sink the app's tracer ends its spans into.

func (OTLPExporter) Stats
func (OTLPExporter) Stats() []OTLPStatsValue

Stats is what each signal's queue holds, has sent and has lost.

type OTLPMeterValue

OTLPMeterValue is the product's own meter on the export: the SDK's metrics.FullMeter held as any, as OTLPSinkValue holds the span sink.

type OTLPMeterValue struct {
	// Meter is the SDK's metrics.FullMeter.
	Meter any
}

type OTLPQueue

OTLPQueue is one signal's queue of the export as the product's CLI opens it (issue #536): its dead letters read, replayed into the live queue, or dropped.

type OTLPQueue interface {
	// Close releases what the queue holds.
	Close() error
	// DeadLetters are at most max of the batches the queue gave up on,
	// oldest first.
	DeadLetters(ctx context.Context, max int) ([]OTLPDeadLetterValue, error)
	// Drop deletes the dead letter id for good. found is false when the
	// queue holds no dead letter id.
	Drop(ctx context.Context, id string) (found bool, err error)
	// Replay moves the dead letter id back into the live queue, its
	// attempts counted afresh: the export sends it again. found is false
	// when the queue holds no dead letter id.
	Replay(ctx context.Context, id string) (found bool, err error)
}

func (OTLPQueue) Close
func (OTLPQueue) Close() error

Close releases what the queue holds.

func (OTLPQueue) DeadLetters
func (OTLPQueue) DeadLetters(ctx context.Context, max int) ([]OTLPDeadLetterValue, error)

DeadLetters are at most max of the batches the queue gave up on, oldest first.

func (OTLPQueue) Drop
func (OTLPQueue) Drop(ctx context.Context, id string) (found bool, err error)

Drop deletes the dead letter id for good. found is false when the queue holds no dead letter id.

func (OTLPQueue) Replay
func (OTLPQueue) Replay(ctx context.Context, id string) (found bool, err error)

Replay moves the dead letter id back into the live queue, its attempts counted afresh: the export sends it again. found is false when the queue holds no dead letter id.

type OTLPSinkValue

OTLPSinkValue is the export's span sink: the SDK's trace.SpanSink held as any, as a MailValue holds a mail — plug names no SDK type, and the core, which names the SDK's trace, takes it back.

type OTLPSinkValue struct {
	// Sink is the SDK's trace.SpanSink.
	Sink any
}

type OTLPStatsValue

OTLPStatsValue is what one signal's queue holds, has sent and has lost, with its bounds.

type OTLPStatsValue struct {
	// LastRetryAfterAt is when the collector last imposed a delay; zero
	// when it never did.
	LastRetryAfterAt time.Time
	// Signal is OTLPTraces or OTLPMetrics.
	Signal           string
	// PendingBytes and MaxBytes are the bytes the queue holds and may hold.
	PendingBytes     int64
	// PendingBytes and MaxBytes are the bytes the queue holds and may hold.
	MaxBytes         int64
	// LastRetryAfter is the last delay the collector imposed.
	LastRetryAfter   time.Duration
	// Pending and MaxBatches are the batches the queue holds and may hold.
	Pending          int
	// Pending and MaxBatches are the batches the queue holds and may hold.
	MaxBatches       int
	// Enqueued, Sent and Retries count the batches kept, sent and the
	// attempts made again.
	Enqueued         uint64
	// Enqueued, Sent and Retries count the batches kept, sent and the
	// attempts made again.
	Sent             uint64
	// Enqueued, Sent and Retries count the batches kept, sent and the
	// attempts made again.
	Retries          uint64
	// Dropped, Expired and DeadLettered count the batches lost to a bound,
	// to their age and to a permanent refusal.
	Dropped          uint64
	// Dropped, Expired and DeadLettered count the batches lost to a bound,
	// to their age and to a permanent refusal.
	Expired          uint64
	// Dropped, Expired and DeadLettered count the batches lost to a bound,
	// to their age and to a permanent refusal.
	DeadLettered     uint64
	// Durable reports whether the queue outlives the process: false in
	// memory — no directory, or a platform whose durable queue the SDK
	// refuses.
	Durable          bool
}

type QueueConfig

QueueConfig is what the framework asks of one queue: where it lies, its policy, the app's clock, and for a mailer's outbox the sealing of what it keeps.

type QueueConfig struct {
	// Name names the queue's node in a refusal: the consumer's or the
	// mailer's node ID.
	Name       string
	// Dir is the directory a file queue lies in; with no Database and no
	// Dir, the queue is in memory.
	Dir        string
	// Database keeps the queue, nil when Dir or memory does: a scope the
	// store subsystem's Database opened, whose transaction a publication in
	// it joins.
	Database   Database
	// Table is the queue's table on Database.
	Table      string
	// Policy is how the queue leases, retries and bounds its messages.
	Policy     QueuePolicyValue
	// Clock is the app's clock, which the queue stamps and waits on.
	Clock      Clock
	// Seal, when set, seals every payload on its way in — a mail's, in a
	// mailer's outbox on a database —, and Unseal opens one on its way out;
	// MaxPayload bounds a payload before it is sealed.
	Seal       func(ctx context.Context, payload []byte) ([]byte, error)
	// Unseal is the payload a box holds, the box as it lies when it does
	// not open.
	Unseal     func(ctx context.Context, box []byte) []byte
	// MaxPayload bounds a payload Seal seals.
	MaxPayload int
	// Wrap, when a test sets it, stands in front of the queue the subsystem
	// opens: a func(queue.Broker) queue.Broker of the SDK's queue, which
	// the framework's core does not name. Nil in every app a product builds.
	Wrap       any
}

type QueueDriverConfig

QueueDriverConfig is what framework/app/queue plugs into kit: how a consumer's queue opens, the migrations that make its table on a database and add the column its dead letters' trails are kept in, and how a delivery's handler says that no retry can help.

type QueueDriverConfig struct {
	// Open opens one queue, as cfg places it: on a database, in a
	// directory, or in memory.
	Open           func(cfg QueueConfig) (Broker, error)
	// OpenSDK opens one queue as cfg places it, and hands the SDK's
	// queue.Broker itself, held as any: for a subsystem that drives the
	// SDK's queue on its own — the OTLP export's forwarder (issue #537) —,
	// with no consumer, no sealing and no test's wrapper.
	OpenSDK        func(cfg QueueConfig) (any, error)
	// TableMigration is the migration that makes the queue table on a
	// database of the dialect named, at version.
	TableMigration func(dialect string, table string, version uint64) (MigrationValue, error)
	// TrailMigration is the migration that adds the column a dead letter's
	// trail is kept in to a queue table an earlier release made on a
	// database of the dialect named, at version; it does nothing on a table
	// that has it, or that is not there yet.
	TrailMigration func(dialect string, table string, version uint64) (MigrationValue, error)
	// DoNotRetry is err as a delivery's handler returns it when no retry
	// can help: its queue dead-letters the message at once.
	DoNotRetry     func(err error) error
	// NotRetryable reports whether err, a delivery's handler's, says that no
	// retry can help: what DoNotRetry returned, the product's own included.
	NotRetryable   func(err error) bool
}

type QueuePolicyValue

QueuePolicyValue is how a queue leases, retries and bounds its messages: the SDK's queue policy, in the framework's terms.

type QueuePolicyValue struct {
	// VisibilityTimeout is how long a delivery is leased.
	VisibilityTimeout time.Duration
	// RetryDelay is the wait after a message's first failure, doubled after
	// each, up to MaxRetryDelay.
	RetryDelay        time.Duration
	// MaxRetryDelay bounds the wait before a retry; zero leaves it unbound.
	MaxRetryDelay     time.Duration
	// MaxDeliveries is how often a message is delivered before it is
	// dead-lettered.
	MaxDeliveries     int
	// MaxMessageBytes bounds a message; zero is the queue's own bound.
	MaxMessageBytes   int
}

type Refusal

Refusal is a kind of refusal of a store's engine or a database, as the framework words it.

type Refusal uint8

type RefusalError

RefusalError is an engine's refusal of one kind: the error it met, and the kind the framework words it by.

type RefusalError struct {
	// Err is what the engine met.
	Err  error
	// Kind is how the framework words it.
	Kind Refusal
}

func (RefusalError) Error
func (*RefusalError) Error() string

Error is what the engine met's.

func (RefusalError) Unwrap
func (*RefusalError) Unwrap() error

Unwrap is what the engine met.

type Reindexer

Reindexer is an engine on a database that files its index rows again. A sibling of StoreEngine.

type Reindexer interface {
	// Reindex files every record's index rows again.
	Reindex(ctx context.Context) error
}

func (Reindexer) Reindex
func (Reindexer) Reindex(ctx context.Context) error

Reindex files every record's index rows again.

type RenameSpec

RenameSpec is the framework's tables on a database moved to their present names (ADR 0180 step 5): each table — with the tables the document store derives from it, <table>___ix and <table>___vs —, the history of the former version table taken by the present one, and the names that history gives the tables' migrations.

type RenameSpec struct {
	// FormerVersions is the version table the framework's set had: the move
	// holds its migration lock, is recorded there, and drops it once the
	// history is the present table's.
	FormerVersions string
	// Versions is the version table the framework's set has now.
	Versions       string
	// Name labels the move in FormerVersions, at Version.
	Name           string
	// Tables are the tables moved, each from its former name to its present
	// one.
	Tables         []RenameValue
	// Labels are the names of the tables' migrations in the history, each
	// from what the former release recorded to what this one says.
	Labels         []RenameValue
	// Version is the move's version in FormerVersions: above every version
	// the framework gives.
	Version        uint64
}

type RenameValue

RenameValue is one name replaced by another: a table's, or a migration's name in a version table.

type RenameValue struct {
	// From is the former name.
	From string
	// To is the present one.
	To   string
}

type StampValue

StampValue is what a write says about the version it makes: who made it and which command, kept with the version; and whether it changes the document in place, without a version of its own.

type StampValue struct {
	// Meta is kept with the version the write makes.
	Meta    map[string]string
	// InPlace makes the write change the document without making a version.
	InPlace bool
}

type Step

Step is one direction of a migration, run on ex.

type Step func(ctx context.Context, ex Executor) error

type StoreConfig

StoreConfig is what the framework asks of one store's engine: the store, its key and its indexes over documents, where it rests and what it keeps, and how its writes take part in the framework's transactions.

type StoreConfig struct {
	// Name is the store's, as a log line and a rollback name it.
	Name        string
	// Key is a document's key: the product's key function on its type,
	// wrapped once at the declaration. It reads the document's Value, which
	// the engine decodes first unless KeyAtRest gives the key.
	Key         func(d DocumentValue) string
	// KeyAtRest, when set, gives the key of a record as it rests, without
	// decoding it; false when it cannot.
	KeyAtRest   func(raw json.RawMessage) (string, bool)
	// Decode is the entity a document's JSON holds, which the engine keeps
	// as the document's Value.
	Decode      func(raw json.RawMessage) (any, error)
	// Indexes are the store's secondary indexes.
	Indexes     []IndexSpec
	// Data is the data directory the store rests in — the SDK's writable
	// file system, which the engine asserts — and Path its snapshot there;
	// a nil Data and a nil Database keep the store in memory.
	Data        fs.FS
	// Path is the store's snapshot in Data.
	Path        string
	// Database keeps the store, nil when the data directory or memory does:
	// a scope the store subsystem's Database opened.
	Database    Database
	// Table is the store's table on Database.
	Table       string
	// IndexKey is the key a table's index keys are hashed under, nil for
	// none: an index key reaches the table as its keyed hash.
	IndexKey    func(index string, key string) []byte
	// Call is the context one call of the engine on Database runs with: on
	// the transaction ctx carries for it, else on the pool, within the
	// database's timeout; done ends it.
	Call        func(ctx context.Context, write bool) (call context.Context, done func(), err error)
	// Versions is how many former versions of each record the engine keeps,
	// none when zero; Clock stamps them.
	Versions    int
	// Clock is the app's clock, which stamps a version.
	Clock       func() time.Time
	// Held reports whether a record's versions are held, and no write may
	// prune them: asked with the write's context, on a database inside its
	// transaction.
	Held        func(ctx context.Context, key string) bool
	// Stamp is what a write under ctx says about the version it makes.
	Stamp       func(ctx context.Context) StampValue
	// Transaction is the framework's transaction, which the engine's writes take part
	// in.
	Transaction Transaction
}

type StoreDriverConfig

StoreDriverConfig is what framework/app/store plugs into kit: how a store's engine opens, how the framework opens its scope on a database, and the migration that makes one of the framework's tables.

type StoreDriverConfig struct {
	// Open opens the engine of one store, as cfg places it: loaded from the
	// data directory, empty in memory, or on a database.
	Open           func(cfg StoreConfig) (StoreEngine, error)
	// Database opens the framework's scope on one database's pool.
	Database       func(cfg DatabaseConfig) (Database, error)
	// TableMigration is the migration that makes the table t on a database
	// of the dialect named, at version.
	TableMigration func(dialect string, t TableSpec, version uint64) (MigrationValue, error)
	// FormerTables are the tables of plan still under a former name on db —
	// its former version table among them —, read from the database's
	// catalogue, sorted: what RenameTables would move; none once moved.
	FormerTables   func(ctx context.Context, db Database, plan RenameSpec) ([]string, error)
	// RenameTables moves the tables of plan to their present names on db
	// (ADR 0180 step 5), under the migration lock of plan's former version
	// table and in the transaction that records the move there, and returns
	// the tables it moved; none when nothing was left under a former name.
	// A table whose present name is taken too is a [RefusalRenameTarget],
	// and nothing moves.
	RenameTables   func(ctx context.Context, db Database, plan RenameSpec) ([]string, error)
}

type StoreEngine

StoreEngine is what a store runs on, over documents (ADR 0179 §2): the non-generic engine under Store[T]. Its refusals are the framework's (Refusal): the engine translates the SDK's before they reach the core. Every call takes the caller's context, which carries the transaction the call joins. It grows by the sibling interfaces below, never by a method (the SDK's ADR 0039).

type StoreEngine interface {
	// Close releases the engine.
	Close() error
	// Count says how many documents the store holds.
	Count(ctx context.Context) (int, error)
	// Delete removes the document under key.
	Delete(ctx context.Context, key string) error
	// Entries returns up to limit documents as they rest, in key order.
	Entries(ctx context.Context, limit int) ([]json.RawMessage, error)
	// Filter returns the documents keep accepts, in key order.
	Filter(ctx context.Context, keep func(d DocumentValue) bool) ([]DocumentValue, error)
	// Find returns the documents an index files under key, in key order.
	Find(ctx context.Context, index string, key string) ([]DocumentValue, error)
	// Get returns the document under key.
	Get(ctx context.Context, key string) (DocumentValue, error)
	// List returns every document, in key order.
	List(ctx context.Context) ([]DocumentValue, error)
	// Lookup returns the document a unique index files under key.
	Lookup(ctx context.Context, index string, key string) (DocumentValue, error)
	// Update applies fn to the document under key and stores the result,
	// atomically with respect to every other write of the store.
	Update(ctx context.Context, key string, fn func(d *DocumentValue) error) (DocumentValue, error)
	// Watch registers the functions told the key of every document written
	// and deleted, once the write stands.
	Watch(onWrite func(key string), onDelete func(key string))
	// Write stores d as mode says. The document and its index keys are kept
	// together, or neither.
	Write(ctx context.Context, d DocumentValue, mode WriteMode) error
}

func (StoreEngine) Close
func (StoreEngine) Close() error

Close releases the engine.

func (StoreEngine) Count
func (StoreEngine) Count(ctx context.Context) (int, error)

Count says how many documents the store holds.

func (StoreEngine) Delete
func (StoreEngine) Delete(ctx context.Context, key string) error

Delete removes the document under key.

func (StoreEngine) Entries
func (StoreEngine) Entries(ctx context.Context, limit int) ([]json.RawMessage, error)

Entries returns up to limit documents as they rest, in key order.

func (StoreEngine) Filter
func (StoreEngine) Filter(ctx context.Context, keep func(d DocumentValue) bool) ([]DocumentValue, error)

Filter returns the documents keep accepts, in key order.

func (StoreEngine) Find
func (StoreEngine) Find(ctx context.Context, index string, key string) ([]DocumentValue, error)

Find returns the documents an index files under key, in key order.

func (StoreEngine) Get
func (StoreEngine) Get(ctx context.Context, key string) (DocumentValue, error)

Get returns the document under key.

func (StoreEngine) List
func (StoreEngine) List(ctx context.Context) ([]DocumentValue, error)

List returns every document, in key order.

func (StoreEngine) Lookup
func (StoreEngine) Lookup(ctx context.Context, index string, key string) (DocumentValue, error)

Lookup returns the document a unique index files under key.

func (StoreEngine) Update
func (StoreEngine) Update(ctx context.Context, key string, fn func(d *DocumentValue) error) (DocumentValue, error)

Update applies fn to the document under key and stores the result, atomically with respect to every other write of the store.

func (StoreEngine) Watch
func (StoreEngine) Watch(onWrite func(key string), onDelete func(key string))

Watch registers the functions told the key of every document written and deleted, once the write stands.

func (StoreEngine) Write
func (StoreEngine) Write(ctx context.Context, d DocumentValue, mode WriteMode) error

Write stores d as mode says. The document and its index keys are kept together, or neither.

type StudioDriverConfig

StudioDriverConfig is what framework/app/studio plugs into kit: how the tool's variables are read, and how the Studio's routes mount.

type StudioDriverConfig struct {
	// Env reads what the tool's variables ask of the Studio in this run.
	Env      func(getenv func(string) string) StudioEnvValue
	// Settings are the tool's variables as the settings of a run show them,
	// in order, each with its value as the run resolved it and where it
	// came from: the product's code, the environment, or the framework's default.
	Settings func(getenv func(string) string, state StudioStateValue) []model.Setting
	// Forced are the variables kit dev says it set itself for this launch,
	// as it names them; the framework labels only those it lets kit dev set.
	Forced   func(getenv func(string) string) []string
	// DevBuild is what kit dev said about the build it launched, nil when
	// the process was not started by kit dev.
	DevBuild func(getenv func(string) string) *model.DevBuild
	// Mount registers the Studio's routes on mux, each behind the Studio's
	// guard, reading the running app through host.
	Mount    func(mux *http.ServeMux, host StudioHost)
}

type StudioEnvValue

StudioEnvValue is what the tool's variables ask of the Studio: their zero value is a run in which none is set.

type StudioEnvValue struct {
	// Studio is what the environment says of the Studio: on — which
	// production refuses —, off, or empty when it says neither.
	Studio     string
	// Remote: the Studio answers a client that is not on this machine.
	Remote     bool
	// NoAnalysis: the environment turns the static analysis off.
	NoAnalysis bool
}

type StudioHost

StudioHost is the running app, as the Studio's routes read it and answer through it.

type StudioHost interface {
	// AllowedHost reports whether a request's Host, its port, brackets and
	// case removed, may reach the Studio.
	AllowedHost(host string) bool
	// Databases are the app's databases, each checked and its migrations
	// read again now.
	Databases(ctx context.Context) []model.Database
	// Debug logs, at the debug level, a failure nobody is told of.
	Debug(ctx context.Context, message string, err error)
	// Fail answers an internal error, saying message and nothing of the
	// error.
	Fail(w http.ResponseWriter, message string)
	// Forbid answers that the caller may not reach the Studio, saying
	// message.
	Forbid(w http.ResponseWriter, message string)
	// Former are the former values of the record under key in store, as
	// the Studio's data view shows them.
	Former(ctx context.Context, store string, key string) (model.RecordHistory, error)
	// Graph is the app's graph, as it is now.
	Graph() *model.Graph
	// Instances are a workflow's entities and where each is; false for no
	// such workflow.
	Instances(workflow string) ([]model.Instance, bool)
	// Invalid is the framework's answer to a request the caller must change, saying
	// message.
	Invalid(message string) error
	// Items are a store's latest entities, redacted as payloads are; false
	// for no such store.
	Items(store string) ([]json.RawMessage, bool)
	// Locate says where the function fn, at file:line, lies in the
	// product's own module; nil anywhere else.
	Locate(file string, line int, fn string) *model.Source
	// Logs are the latest records the product logged, those of a trace or
	// a node and from a level when given, at most limit — a default when
	// it is empty; a level or a limit the app does not take is refused.
	Logs(trace string, node string, level string, limit string) ([]model.LogRecord, error)
	// Mail is one mail, whole when its mailer keeps bodies; false when no
	// mailer remembers it.
	Mail(id string) (model.MailMessage, bool)
	// Mails are every mailer's latest mails, at most limit of each.
	Mails(limit int) []model.MailSummary
	// NotFound is the framework's answer to a request for what does not exist,
	// saying message.
	NotFound(message string) error
	// Now is the time on the app's clock.
	Now() time.Time
	// Phase is where the app is in its life, as the graph says it.
	Phase() string
	// Privacy is what the Studio's Privacy page shows.
	Privacy(ctx context.Context) (model.Privacy, error)
	// ProfileUnreadable is the framework's refusal of a profile the process could
	// not read: public says which, cause why, for the logs.
	ProfileUnreadable(public string, cause error) error
	// Remote reports whether the Studio answers a client that is not on
	// this machine.
	Remote() bool
	// Reply answers r with body, a JSON document, or with err as the framework
	// answers an error.
	Reply(w http.ResponseWriter, r *http.Request, body json.RawMessage, err error)
	// Revisions are the versions of the record under key in store, and
	// what changed from version from to version to when both are given.
	Revisions(ctx context.Context, store string, key string, from string, to string) (model.RecordVersions, error)
	// Source is a file the graph names, of the product's Go module or of
	// the one module names: a regular file within the bound, never a link;
	// false for any other name.
	Source(ctx context.Context, module string, file string) ([]byte, bool)
	// Stopping is closed when the app ends its live streams.
	Stopping() <-chan struct{}
	// Stores reports whether the app runs on the store subsystem: the
	// Studio's routes on the stores and the databases are mounted only then.
	Stores() bool
	// Subscribe streams the app's live events until cancel is called.
	Subscribe() (events <-chan model.Event, cancel func())
	// Trace is one trace, while the app keeps it.
	Trace(id string) (model.Trace, bool)
	// Traces are the latest traces the app keeps, at most limit, those of
	// root's trace or through node when either is given.
	Traces(limit int, root string, node string) []model.Trace
	// Trash is a page of store's trash, from offset and at most limit
	// records — defaults when they are empty.
	Trash(ctx context.Context, store string, offset string, limit string) (model.StoreTrash, error)
}

func (StudioHost) AllowedHost
func (StudioHost) AllowedHost(host string) bool

AllowedHost reports whether a request's Host, its port, brackets and case removed, may reach the Studio.

func (StudioHost) Databases
func (StudioHost) Databases(ctx context.Context) []model.Database

Databases are the app's databases, each checked and its migrations read again now.

func (StudioHost) Debug
func (StudioHost) Debug(ctx context.Context, message string, err error)

Debug logs, at the debug level, a failure nobody is told of.

func (StudioHost) Fail
func (StudioHost) Fail(w http.ResponseWriter, message string)

Fail answers an internal error, saying message and nothing of the error.

func (StudioHost) Forbid
func (StudioHost) Forbid(w http.ResponseWriter, message string)

Forbid answers that the caller may not reach the Studio, saying message.

func (StudioHost) Former
func (StudioHost) Former(ctx context.Context, store string, key string) (model.RecordHistory, error)

Former are the former values of the record under key in store, as the Studio's data view shows them.

func (StudioHost) Graph
func (StudioHost) Graph() *model.Graph

Graph is the app's graph, as it is now.

func (StudioHost) Instances
func (StudioHost) Instances(workflow string) ([]model.Instance, bool)

Instances are a workflow's entities and where each is; false for no such workflow.

func (StudioHost) Invalid
func (StudioHost) Invalid(message string) error

Invalid is the framework's answer to a request the caller must change, saying message.

func (StudioHost) Items
func (StudioHost) Items(store string) ([]json.RawMessage, bool)

Items are a store's latest entities, redacted as payloads are; false for no such store.

func (StudioHost) Locate
func (StudioHost) Locate(file string, line int, fn string) *model.Source

Locate says where the function fn, at file:line, lies in the product's own module; nil anywhere else.

func (StudioHost) Logs
func (StudioHost) Logs(trace string, node string, level string, limit string) ([]model.LogRecord, error)

Logs are the latest records the product logged, those of a trace or a node and from a level when given, at most limit — a default when it is empty; a level or a limit the app does not take is refused.

func (StudioHost) Mail
func (StudioHost) Mail(id string) (model.MailMessage, bool)

Mail is one mail, whole when its mailer keeps bodies; false when no mailer remembers it.

func (StudioHost) Mails
func (StudioHost) Mails(limit int) []model.MailSummary

Mails are every mailer's latest mails, at most limit of each.

func (StudioHost) NotFound
func (StudioHost) NotFound(message string) error

NotFound is the framework's answer to a request for what does not exist, saying message.

func (StudioHost) Now
func (StudioHost) Now() time.Time

Now is the time on the app's clock.

func (StudioHost) Phase
func (StudioHost) Phase() string

Phase is where the app is in its life, as the graph says it.

func (StudioHost) Privacy
func (StudioHost) Privacy(ctx context.Context) (model.Privacy, error)

Privacy is what the Studio's Privacy page shows.

func (StudioHost) ProfileUnreadable
func (StudioHost) ProfileUnreadable(public string, cause error) error

ProfileUnreadable is the framework's refusal of a profile the process could not read: public says which, cause why, for the logs.

func (StudioHost) Remote
func (StudioHost) Remote() bool

Remote reports whether the Studio answers a client that is not on this machine.

func (StudioHost) Reply
func (StudioHost) Reply(w http.ResponseWriter, r *http.Request, body json.RawMessage, err error)

Reply answers r with body, a JSON document, or with err as the framework answers an error.

func (StudioHost) Revisions
func (StudioHost) Revisions(ctx context.Context, store string, key string, from string, to string) (model.RecordVersions, error)

Revisions are the versions of the record under key in store, and what changed from version from to version to when both are given.

func (StudioHost) Source
func (StudioHost) Source(ctx context.Context, module string, file string) ([]byte, bool)

Source is a file the graph names, of the product's Go module or of the one module names: a regular file within the bound, never a link; false for any other name.

func (StudioHost) Stopping
func (StudioHost) Stopping() <-chan struct{}

Stopping is closed when the app ends its live streams.

func (StudioHost) Stores
func (StudioHost) Stores() bool

Stores reports whether the app runs on the store subsystem: the Studio's routes on the stores and the databases are mounted only then.

func (StudioHost) Subscribe
func (StudioHost) Subscribe() (events <-chan model.Event, cancel func())

Subscribe streams the app's live events until cancel is called.

func (StudioHost) Trace
func (StudioHost) Trace(id string) (model.Trace, bool)

Trace is one trace, while the app keeps it.

func (StudioHost) Traces
func (StudioHost) Traces(limit int, root string, node string) []model.Trace

Traces are the latest traces the app keeps, at most limit, those of root's trace or through node when either is given.

func (StudioHost) Trash
func (StudioHost) Trash(ctx context.Context, store string, offset string, limit string) (model.StoreTrash, error)

Trash is a page of store's trash, from offset and at most limit records — defaults when they are empty.

type StudioStateValue

StudioStateValue is what a run resolved of the Studio, and what the product's code chose of it: what the settings show of the tool's variables.

type StudioStateValue struct {
	// StudioOption and AnalyzeOption are the product's code's choice of the
	// Studio and of the static analysis, which wins over the environment;
	// nil when the code chose nothing.
	StudioOption  *bool
	// StudioOption and AnalyzeOption are the product's code's choice of the
	// Studio and of the static analysis, which wins over the environment;
	// nil when the code chose nothing.
	AnalyzeOption *bool
	// Studio, Remote and Analyze are the Studio's switches, as resolved and
	// as the settings spell them: on or off.
	Studio        string
	// Studio, Remote and Analyze are the Studio's switches, as resolved and
	// as the settings spell them: on or off.
	Remote        string
	// Studio, Remote and Analyze are the Studio's switches, as resolved and
	// as the settings spell them: on or off.
	Analyze       string
}

type TableSpec

TableSpec is one of the framework's tables on a database, as the store subsystem's migration makes it: a store's, or a store's versions beside the store's table VersionsOf. A consumer's queue's table is the queue subsystem's (QueueDriverConfig's TableMigration).

type TableSpec struct {
	// Name is the table's.
	Name       string
	// VersionsOf is, for a store's versions, the store's table, from which
	// the versions' table is named.
	VersionsOf string
}

type Ticker

Ticker is a ticker of a Clock.

type Ticker interface {
	// C receives the clock's instant at each tick.
	C() <-chan time.Time
	// Reset makes the ticker fire every d.
	Reset(d time.Duration)
	// Stop stops the ticker.
	Stop()
}

func (Ticker) C
func (Ticker) C() <-chan time.Time

C receives the clock's instant at each tick.

func (Ticker) Reset
func (Ticker) Reset(d time.Duration)

Reset makes the ticker fire every d.

func (Ticker) Stop
func (Ticker) Stop()

Stop stops the ticker.

type Timer

Timer is a timer of a Clock.

type Timer interface {
	// C receives the clock's instant when the timer fires.
	C() <-chan time.Time
	// Reset makes the timer fire once d passed, and reports whether it had
	// not fired.
	Reset(d time.Duration) bool
	// Stop stops the timer, and reports whether it had not fired.
	Stop() bool
}

func (Timer) C
func (Timer) C() <-chan time.Time

C receives the clock's instant when the timer fires.

func (Timer) Reset
func (Timer) Reset(d time.Duration) bool

Reset makes the timer fire once d passed, and reports whether it had not fired.

func (Timer) Stop
func (Timer) Stop() bool

Stop stops the timer, and reports whether it had not fired.

type TombstoneValue

TombstoneValue is one record in a store's trash: its key, and when it was trashed.

type TombstoneValue struct {
	// Key is the trashed record's key.
	Key string
	// At is when the record was trashed, in UTC.
	At  time.Time
}

type Transaction

Transaction is the framework's transaction as a store's engine takes part in it (ADR 0139, ADR 0178): the core implements it, an engine calls it with its caller's context.

type Transaction interface {
	// AtCommit holds fn until the transaction ctx carries commits, and
	// reports whether it did: false outside one, where the caller runs it
	// now.
	AtCommit(ctx context.Context, fn func()) bool
	// Local reports whether ctx runs in a transaction that holds the data's
	// writer turn: a write in the data directory or in memory then records
	// what it replaces.
	Local(ctx context.Context) bool
	// Retell keeps fn, which announces a write on a database again when the
	// transaction ctx carries rolls it back.
	Retell(ctx context.Context, fn func())
	// Undo keeps restore, which a rollback of the transaction ctx carries
	// runs; nothing outside one. store names the store in a log line.
	Undo(ctx context.Context, store string, restore func(ctx context.Context) error)
}

func (Transaction) AtCommit
func (Transaction) AtCommit(ctx context.Context, fn func()) bool

AtCommit holds fn until the transaction ctx carries commits, and reports whether it did: false outside one, where the caller runs it now.

func (Transaction) Local
func (Transaction) Local(ctx context.Context) bool

Local reports whether ctx runs in a transaction that holds the data's writer turn: a write in the data directory or in memory then records what it replaces.

func (Transaction) Retell
func (Transaction) Retell(ctx context.Context, fn func())

Retell keeps fn, which announces a write on a database again when the transaction ctx carries rolls it back.

func (Transaction) Undo
func (Transaction) Undo(ctx context.Context, store string, restore func(ctx context.Context) error)

Undo keeps restore, which a rollback of the transaction ctx carries runs; nothing outside one. store names the store in a log line.

type TransitionSpec

TransitionSpec declares one transition: an event's, a timer's after a delay or at an instant the entity carries, or a guard's.

type TransitionSpec struct {
	// Instant is when a deadline's transition comes due, false for no
	// instant for now; set for WorkflowTriggerDeadline.
	Instant func(e WorkflowEntityValue) (time.Time, bool)
	// Guard is the condition a guard's transition waits for; set for
	// WorkflowTriggerGuard.
	Guard   func(e WorkflowEntityValue) bool
	// Event names the transition.
	Event   string
	// From is the state it leaves.
	From    string
	// To is the state it enters.
	To      string
	// Delay is how long a delay's transition waits in From.
	Delay   time.Duration
	// Trigger is what fires it: an event, a delay, a deadline or a guard.
	Trigger WorkflowTrigger
}

type Translator

Translator says the framework's sentences in the languages after English, which only the Studio shows, in its reader's language.

type Translator interface {
	// Keys are the keys of lang's catalogue, sorted; nil for a language
	// it does not speak.
	Keys(lang string) []string
	// Languages are the languages it speaks after English, in order.
	Languages() []string
	// Render is the sentence of key in lang, its placeholders filled from
	// args by name; a key the catalogue lacks, or a name the sentence
	// takes that args does not give, is an error.
	Render(lang string, key string, args map[string]string) (string, error)
}

func (Translator) Keys
func (Translator) Keys(lang string) []string

Keys are the keys of lang's catalogue, sorted; nil for a language it does not speak.

func (Translator) Languages
func (Translator) Languages() []string

Languages are the languages it speaks after English, in order.

func (Translator) Render
func (Translator) Render(lang string, key string, args map[string]string) (string, error)

Render is the sentence of key in lang, its placeholders filled from args by name; a key the catalogue lacks, or a name the sentence takes that args does not give, is an error.

type Trasher

Trasher is an engine that keeps a trash. A sibling of StoreEngine.

type Trasher interface {
	// Purge empties the trash of the record trashed under key, its versions
	// with it.
	Purge(ctx context.Context, key string) error
	// Tombstones are every record in the trash, in key order.
	Tombstones(ctx context.Context) ([]TombstoneValue, error)
	// Trash moves the record under key to the trash: gone from every read,
	// its index keys freed, its versions kept.
	Trash(ctx context.Context, key string) error
	// Untrash brings the record trashed under key back as it was.
	Untrash(ctx context.Context, key string) error
}

func (Trasher) Purge
func (Trasher) Purge(ctx context.Context, key string) error

Purge empties the trash of the record trashed under key, its versions with it.

func (Trasher) Tombstones
func (Trasher) Tombstones(ctx context.Context) ([]TombstoneValue, error)

Tombstones are every record in the trash, in key order.

func (Trasher) Trash
func (Trasher) Trash(ctx context.Context, key string) error

Trash moves the record under key to the trash: gone from every read, its index keys freed, its versions kept.

func (Trasher) Untrash
func (Trasher) Untrash(ctx context.Context, key string) error

Untrash brings the record trashed under key back as it was.

type TxOptionsValue

TxOptionsValue is what app.Transact asks of a database transaction: an isolation level — the zero value the database's default — and whether it only reads. A savepoint is given the zero value.

type TxOptionsValue struct {
	// Isolation is the transaction's isolation level; zero is the database's default.
	Isolation sql.IsolationLevel
	// ReadOnly tells the database the transaction only reads.
	ReadOnly  bool
}

type VersionKeeper

VersionKeeper is an engine that keeps its records' versions. A sibling of StoreEngine.

type VersionKeeper interface {
	// RewriteVersions rewrites the former versions of the record under key
	// as fn returns them: fn may drop a version or change what one holds,
	// never add or renumber one.
	RewriteVersions(ctx context.Context, key string, fn func(vs []VersionValue) ([]VersionValue, error)) error
	// StoredVersions are the versions of the record under key, newest
	// first, the current one first.
	StoredVersions(ctx context.Context, key string) ([]VersionValue, error)
}

func (VersionKeeper) RewriteVersions
func (VersionKeeper) RewriteVersions(ctx context.Context, key string, fn func(vs []VersionValue) ([]VersionValue, error)) error

RewriteVersions rewrites the former versions of the record under key as fn returns them: fn may drop a version or change what one holds, never add or renumber one.

func (VersionKeeper) StoredVersions
func (VersionKeeper) StoredVersions(ctx context.Context, key string) ([]VersionValue, error)

StoredVersions are the versions of the record under key, newest first, the current one first.

type VersionValue

VersionValue is one version of a record: its number, when the write that made it ran, what that write said about it, and the record as it held it.

type VersionValue struct {
	// Number counts a record's versions from 1.
	Number uint64
	// At is when the write that made the version ran, in UTC.
	At     time.Time
	// Meta is what the write said about it: who made it, which command.
	Meta   map[string]string
	// JSON is the record as the version holds it.
	JSON   json.RawMessage
}

type VersionWeightValue

VersionWeightValue is what a store keeps beyond the records it holds: its former versions and its trash, counted and weighed.

type VersionWeightValue struct {
	// Former is how many former versions the store keeps.
	Former  int
	// Trashed is how many records are in the trash.
	Trashed int
	// Bytes is what the former versions and the trashed records weigh.
	Bytes   int64
}

type VersionWeighter

VersionWeighter is an engine that says what its records' versions weigh. A sibling of StoreEngine.

type VersionWeighter interface {
	// VersionWeight is what the store's versions and trash weigh.
	VersionWeight(ctx context.Context) (VersionWeightValue, error)
}

func (VersionWeighter) VersionWeight
func (VersionWeighter) VersionWeight(ctx context.Context) (VersionWeightValue, error)

VersionWeight is what the store's versions and trash weigh.

type WordsConfig

WordsConfig is what framework/app/studio plugs into kit: how the framework's catalogues in the languages after English open.

type WordsConfig struct {
	// Open reads and compiles the catalogue of every language after
	// English, each falling back to english — the framework's own sentences, by
	// key, as its core holds them; a catalogue that does not decode or
	// does not compile is refused.
	Open func(english map[string]string) (Translator, error)
}

type WorkflowChangeValue

WorkflowChangeValue is one stored transition: the entity as stored after it, the states it left and entered, what fired it, who and when.

type WorkflowChangeValue struct {
	// At is when it happened.
	At      time.Time
	// Entity is the entity, as stored after the transition.
	Entity  WorkflowEntityValue
	// Key is the entity's key.
	Key     string
	// Event is the transition's name; WorkflowCreateEvent for Start.
	Event   string
	// From is the state left, "" on creation.
	From    string
	// To is the state entered.
	To      string
	// Actor is who fired it, "" for the loop.
	Actor   string
	// Trigger is what fired it.
	Trigger WorkflowTrigger
}

type WorkflowConfig

WorkflowConfig is one workflow as its engine runs it: its states and transitions, its hooks, the store and the journal it runs over, and how the app's loop, clock and spans see it.

type WorkflowConfig struct {
	// Store is the workflow's entities, as the engine reads and writes them.
	Store        WorkflowStore
	// Journal keeps what the engine knows of each entity — its state, since
	// when, its latest transitions —; nil keeps it in memory alone.
	Journal      WorkflowJournal
	// Clock is the app's clock, which the engine stamps and waits on.
	Clock        Clock
	// Actor names, from the context of a transition someone fired, who
	// fired it.
	Actor        func(ctx context.Context) string
	// Observe brackets each transition the loop fires: the context it runs
	// with, and the function told how it ended.
	Observe      func(ctx context.Context, f WorkflowFiringValue) (context.Context, func(err error))
	// Report receives what the engine reports and no caller's return value
	// carries: an OnTransition hook that failed, a panic, a journal's write
	// that failed.
	Report       func(ctx context.Context, err error)
	// OnLoop is told each run of the loop, and each wait.
	OnLoop       func(e WorkflowLoopEventValue)
	// Initial is the state Start enters an entity in.
	Initial      string
	// Transitions are the declared transitions, in declaration order.
	Transitions  []TransitionSpec
	// OnEnter are the hooks run as an entity enters a state, in
	// declaration order.
	OnEnter      []EnterHookSpec
	// OnTransition are the hooks run after every stored transition, in
	// declaration order.
	OnTransition []func(ctx context.Context, c WorkflowChangeValue) error
	// MinGap is the least a wake for a due transition waits after a run.
	MinGap       time.Duration
	// BackoffBase is the wait after a run that failed, doubled after each,
	// up to BackoffMax.
	BackoffBase  time.Duration
	// BackoffMax bounds the wait after a run that failed.
	BackoffMax   time.Duration
	// MaxHistory caps the transitions remembered per entity.
	MaxHistory   int
}

type WorkflowDriverConfig

WorkflowDriverConfig is what framework/app/workflow plugs into kit: how a workflow's engine opens, and how the framework tells the engine's failures apart.

type WorkflowDriverConfig struct {
	// Open opens the engine of one workflow, as cfg declares it: it reads
	// the journal and every entity of the store once.
	Open   func(ctx context.Context, cfg *WorkflowConfig) (WorkflowEngine, error)
	// Failed reports whether err, or an error it wraps, is the engine's
	// failure of kind: the SDK's sentinels stay in the subsystem, and the
	// error keeps the fields the engine gave it.
	Failed func(err error, kind WorkflowFailure) bool
}

type WorkflowEngine

WorkflowEngine is one workflow's engine as the framework's core uses it: the transitions code fires, what a write of the store tells it, what it counts and records, and its loop.

type WorkflowEngine interface {
	// Census counts the entities per state.
	Census() map[string]int
	// Changed tells the engine the entity under key was written.
	Changed(ctx context.Context, key string) error
	// Deleted tells the engine the entity under key was deleted.
	Deleted(ctx context.Context, key string) error
	// Fire moves the entity under key along the event's transition leaving
	// its state.
	Fire(ctx context.Context, key string, event string) (WorkflowEntityValue, error)
	// Records are what the engine knows of each entity.
	Records() []WorkflowRecordValue
	// Run runs the loop that fires the timers and the guards, until ctx
	// ends.
	Run(ctx context.Context) error
	// Start enters e in the workflow, in the initial state: its OnEnter
	// hooks run, then it is inserted in the store.
	Start(ctx context.Context, e WorkflowEntityValue) (WorkflowEntityValue, error)
}

func (WorkflowEngine) Census
func (WorkflowEngine) Census() map[string]int

Census counts the entities per state.

func (WorkflowEngine) Changed
func (WorkflowEngine) Changed(ctx context.Context, key string) error

Changed tells the engine the entity under key was written.

func (WorkflowEngine) Deleted
func (WorkflowEngine) Deleted(ctx context.Context, key string) error

Deleted tells the engine the entity under key was deleted.

func (WorkflowEngine) Fire
func (WorkflowEngine) Fire(ctx context.Context, key string, event string) (WorkflowEntityValue, error)

Fire moves the entity under key along the event's transition leaving its state.

func (WorkflowEngine) Records
func (WorkflowEngine) Records() []WorkflowRecordValue

Records are what the engine knows of each entity.

func (WorkflowEngine) Run
func (WorkflowEngine) Run(ctx context.Context) error

Run runs the loop that fires the timers and the guards, until ctx ends.

func (WorkflowEngine) Start
func (WorkflowEngine) Start(ctx context.Context, e WorkflowEntityValue) (WorkflowEntityValue, error)

Start enters e in the workflow, in the initial state: its OnEnter hooks run, then it is inserted in the store.

type WorkflowEntityValue

WorkflowEntityValue is one entity as a workflow's engine holds it: the product's, kept as any — the workflow's typed facade asserts it to its type —, and its state as the facade spells it, which the engine reads and sets.

type WorkflowEntityValue struct {
	// Value is the product's entity.
	Value any
	// State is the entity's state, spelled.
	State string
}

type WorkflowFailure

WorkflowFailure is a failure of a workflow's engine, as the framework words it.

type WorkflowFailure uint8

type WorkflowFiringValue

WorkflowFiringValue is one transition the loop is about to fire: the entity's key, the event, the states it leaves and enters, and its trigger.

type WorkflowFiringValue struct {
	// Key is the entity's key.
	Key     string
	// Event is the transition's name.
	Event   string
	// From is the state it leaves.
	From    string
	// To is the state it enters.
	To      string
	// Trigger is what fires it.
	Trigger WorkflowTrigger
}

type WorkflowJournal

WorkflowJournal is the port a workflow's engine keeps what it knows of each entity in: the workflow's file under the data directory, or its table on the database that keeps its store.

type WorkflowJournal interface {
	// Delete forgets the records of keys; one already gone is no error.
	Delete(ctx context.Context, keys ...string) error
	// Load reads every record the journal kept.
	Load(ctx context.Context) ([]WorkflowRecordValue, error)
	// Save keeps records, in the transaction ctx carries for a database.
	Save(ctx context.Context, records ...WorkflowRecordValue) error
}

func (WorkflowJournal) Delete
func (WorkflowJournal) Delete(ctx context.Context, keys ...string) error

Delete forgets the records of keys; one already gone is no error.

func (WorkflowJournal) Load
func (WorkflowJournal) Load(ctx context.Context) ([]WorkflowRecordValue, error)

Load reads every record the journal kept.

func (WorkflowJournal) Save
func (WorkflowJournal) Save(ctx context.Context, records ...WorkflowRecordValue) error

Save keeps records, in the transaction ctx carries for a database.

type WorkflowLoopEvent

WorkflowLoopEvent is what a workflow's loop reports.

type WorkflowLoopEvent uint8

type WorkflowLoopEventValue

WorkflowLoopEventValue is what a workflow's loop reports: a run started, a run ended, a wait.

type WorkflowLoopEventValue struct {
	// Err is what a run could not fire, nil for nothing.
	Err     error
	// Started is when the run started.
	Started time.Time
	// Ended is when the run ended.
	Ended   time.Time
	// Next is when the loop wakes next, zero for no transition due.
	Next    time.Time
	// Kind is what the event reports.
	Kind    WorkflowLoopEvent
	// Wake is why the run started.
	Wake    WorkflowWake
}

type WorkflowRecordValue

WorkflowRecordValue is what a workflow's engine knows of one entity: its state, since when, and its latest transitions, oldest first.

type WorkflowRecordValue struct {
	// Entered is when the entity entered its state.
	Entered time.Time
	// Key is the entity's key.
	Key     string
	// State is the entity's state.
	State   string
	// History are its latest transitions, oldest first.
	History []WorkflowStepValue
}

type WorkflowStepValue

WorkflowStepValue is one transition of an entity's history: the event, the states it left and entered, what fired it, who and when.

type WorkflowStepValue struct {
	// At is when it happened.
	At      time.Time
	// Event is the transition's name.
	Event   string
	// From is the state left, "" on creation.
	From    string
	// To is the state entered.
	To      string
	// Actor is who fired it, "" for the loop.
	Actor   string
	// Trigger is what fired it.
	Trigger WorkflowTrigger
}

type WorkflowStore

WorkflowStore is the port a workflow's engine reads and writes its entities through: the workflow's store.

type WorkflowStore interface {
	// All yields every entity of the store.
	All(ctx context.Context) iter.Seq2[WorkflowEntityValue, error]
	// Get reads the entity under key; false when there is none.
	Get(ctx context.Context, key string) (WorkflowEntityValue, bool, error)
	// Insert writes e unless its key is taken; false when it was.
	Insert(ctx context.Context, e WorkflowEntityValue) (bool, error)
	// Key is e's key.
	Key(e WorkflowEntityValue) string
	// Replace writes e over the entity of its key; false when there was
	// none.
	Replace(ctx context.Context, e WorkflowEntityValue) (bool, error)
}

func (WorkflowStore) All
func (WorkflowStore) All(ctx context.Context) iter.Seq2[WorkflowEntityValue, error]

All yields every entity of the store.

func (WorkflowStore) Get
func (WorkflowStore) Get(ctx context.Context, key string) (WorkflowEntityValue, bool, error)

Get reads the entity under key; false when there is none.

func (WorkflowStore) Insert
func (WorkflowStore) Insert(ctx context.Context, e WorkflowEntityValue) (bool, error)

Insert writes e unless its key is taken; false when it was.

func (WorkflowStore) Key
func (WorkflowStore) Key(e WorkflowEntityValue) string

Key is e's key.

func (WorkflowStore) Replace
func (WorkflowStore) Replace(ctx context.Context, e WorkflowEntityValue) (bool, error)

Replace writes e over the entity of its key; false when there was none.

type WorkflowTrigger

WorkflowTrigger is what fires a transition.

type WorkflowTrigger uint8

type WorkflowWake

WorkflowWake is why a run of a workflow's loop started.

type WorkflowWake uint8

type WriteMode

WriteMode says what a write expects to find under the document's key.

type WriteMode int

Generated from docs/api by tools/genindex.

Documentation

Overview

Package plug is where the framework's opt-in subsystems plug in: the HTTP engine, the frontends' file server and the process sampler of the runtime graph (framework/app/server), the Studio — the tool's variables, its routes and the framework's sentences in the languages after English (framework/app/studio) —, the stores and the databases (framework/app/store), the queues (framework/app/queue), the workflows (framework/app/workflow), the mailers (framework/app/mail), the jobs (framework/app/jobs). The framework reads what they registered through the hooks declared here, and imports none of the SDK packages behind them: a product that does not import a subsystem neither links nor initialises its packages.

It is also the contract between the framework's core and the subsystems ADR 0179 takes out of it, as database/sql/driver is between database/sql and a driver: the store subsystem's engine over documents, its siblings, the framework's scope on a database and its migrations (Stores), which framework/app/store sets; the refusals an engine says in the framework's terms (Refusal); what the framework's transactions offer an engine that takes part in them (Transaction); the queue subsystem's brokers and their consumer (Queues), which framework/app/queue sets; the workflow subsystem's engine and the ports it runs on (Workflows), which framework/app/workflow sets; the mail subsystem's outbox and transports (Mail), which framework/app/mail sets; the jobs subsystem's schedules and scheduler (Jobs), which framework/app/jobs sets; the framework's catalogues in the languages after English (Words), and the Studio's routes and the tool's variables (Studio, ADR 0180 step 1), which framework/app/studio sets, the routes reading the running app through a StudioHost the framework gives.

The package imports the standard library and the framework's model only, so that the framework and every subsystem can import it.

Index

Constants

View Source
const (
	// OTLPTraces names the trace signal: an OTLP/JSON
	// ExportTraceServiceRequest.
	OTLPTraces string = "traces"
	// OTLPMetrics names the metrics signal: an OTLP/JSON
	// ExportMetricsServiceRequest.
	OTLPMetrics string = "metrics"
)

The two signals an export forwards, as an OTLPBatchValue names them.

View Source
const (
	// OTLPDropOldest takes the oldest batches out until the new one fits.
	OTLPDropOldest string = "drop-oldest"
	// OTLPDropNewest refuses the new batch.
	OTLPDropNewest string = "drop-newest"
	// OTLPBlock makes the producer wait for room, up to a bound.
	OTLPBlock string = "block"
)

The full policies an export's queue applies, as the setting spells them.

View Source
const (
	// LabelNode is the pprof label naming the node a goroutine works for.
	LabelNode string = "app_node"
	// LabelLoop is the pprof label naming the loop a goroutine belongs to.
	LabelLoop string = "app_loop"
)
View Source
const WorkflowCreateEvent string = "create"

WorkflowCreateEvent is the event of a transition Start fires: an entity entering its workflow.

Variables

View Source
var (
	// NewHTTPServer builds the HTTP engine an app in the server profile
	// serves on; nil until framework/app/server is imported.
	NewHTTPServer atomic.Pointer[func(cfg HTTPConfig) HTTPServer]
	// NewStaticFiles builds the file server of a frontend's tree; nil until
	// framework/app/server is imported.
	NewStaticFiles atomic.Pointer[func(fsys fs.FS, csp string) (http.Handler, error)]
	// SampleProcess samples the running process — its heap, goroutines,
	// collections and CPU time — for the runtime graph a serving app answers;
	// nil until framework/app/server is imported, and the graph then carries
	// no process (ADR 0172).
	SampleProcess atomic.Pointer[func() *model.Process]
)

Jobs is the jobs subsystem: the schedules of the framework's jobs and the scheduler that fires them; nil until framework/app/jobs is imported. A product that declares a job without it is refused at the start (ADR 0179 §6).

Mail is the mail subsystem: the outbox the framework's mailers keep and the transports that empty it; nil until framework/app/mail is imported. A product that declares a mailer without it is refused at the start (ADR 0179 §6).

OTLP is the OTLP export subsystem; nil until framework/app/otlp is imported. A product that declares app.OTLP without it is refused at the start (ADR 0179 §6).

Queues is the queue subsystem: the brokers the framework's consumers' queues run on and the migration of a queue's table on a database; nil until framework/app/queue is imported. A product that declares a topic, a subscription, a watch, a queued command or a mailer whose outbox is on a database without it is refused at the start (ADR 0179 §6).

Stores is the store subsystem: the engines the framework's stores run on, the framework's scope on a database and the migrations of the framework's tables; nil until framework/app/store is imported. A product that declares a store or a database without it is refused at the start (ADR 0179 §6).

Studio is the Studio subsystem: the tool's variables and the Studio's routes; nil until framework/app/studio is imported, and the framework then reads none of the tool's variables and serves no route of the Studio.

Words is the framework's sentences in the languages after English, the catalogues the Studio shows its reader's language from; nil until framework/app/studio is imported, and the framework then speaks English alone. The terminal, the logs and an error read English whatever a program imports (ADR 0179 Q6).

Workflows is the workflow subsystem: the engine the framework's workflows run on; nil until framework/app/workflow is imported. A product that declares a workflow without it is refused at the start (ADR 0179 §6).

Functions

func Refuse

func Refuse(kind Refusal, err error) error

Refuse is err as a refusal of kind.

func Refused

func Refused(err error, kind Refusal) bool

Refused reports whether err, or an error it wraps, is a refusal of kind.

Types

type Broker

type Broker interface {
	// Publish puts payload in the queue: in the transaction ctx carries for
	// its database, when it lives on one.
	Publish(ctx context.Context, payload []byte) error
	// Consume delivers the queue's messages to cfg's handler until ctx ends
	// or the queue's storage fails.
	Consume(ctx context.Context, cfg ConsumeConfig) error
	// DeadLetters are up to maxLetters of the queue's dead letters, oldest
	// first.
	DeadLetters(ctx context.Context, maxLetters int) ([]DeadLetterValue, error)
}

Broker is one queue as the framework's core uses it: a publication, the consumer that delivers it, and its dead letters. It grows by the siblings below.

type Checker

type Checker interface {
	// Check asks the database whether it answers, within its check timeout.
	Check(ctx context.Context) error
}

Checker is a Database that says whether it answers. A sibling of Database.

type Classifier added in v0.59.0

type Classifier interface {
	// Transient reports whether err asks for the transaction to run again.
	Transient(err error) bool
}

Classifier is a Database that says whether a failed transaction is one the database asks to run again: a serialization failure, a deadlock, a lock wait that timed out. app.Transact runs such a transaction again, at its outermost level. A sibling of Database.

type Clock

type Clock interface {
	// Now is the clock's instant.
	Now() time.Time
	// Since is how long ago t was, on the clock.
	Since(t time.Time) time.Duration
	// After is a channel that receives the clock's instant once d passed.
	After(d time.Duration) <-chan time.Time
	// NewTimer is a timer that fires once d passed.
	NewTimer(d time.Duration) Timer
	// NewTicker is a ticker that fires every d.
	NewTicker(d time.Duration) Ticker
	// Sleep waits until d passed.
	Sleep(d time.Duration)
}

Clock is the app's clock as a queue stamps and waits on it: the framework's core hands the one its app runs on, a test's manual clock included.

type ConsumeConfig

type ConsumeConfig struct {
	// Handler handles one delivery: nil acknowledges it, an error has it
	// retried or, through DoNotRetry, dead-lettered at once. Every handler
	// the framework runs tolerates a redelivery.
	Handler func(ctx context.Context, d DeliveryValue) error
	// PollInterval bounds an idle wait.
	PollInterval time.Duration
	// Parallelism is how many deliveries are handled at once.
	Parallelism int
	// BatchSize is how many messages the consumer takes at a time.
	BatchSize int
	// DrainTimeout is how long the handler running when ctx ends may still
	// run before its context is cancelled; zero cancels it at once.
	DrainTimeout time.Duration
	// SettleTimeout bounds each outcome sent once ctx ended, and each lease
	// renewal; zero is the queue's own bound.
	SettleTimeout time.Duration
	// AutoExtend renews the lease of the message a handler runs for as long
	// as it runs.
	AutoExtend bool
	// RetryIn reads, from the error a delivery's handler returned, the delay
	// it asked to be retried after: its queue hands the message back with
	// that delay, the delivery counted. Nil, or false, keeps the queue's own
	// retry delay.
	RetryIn func(err error) (delay time.Duration, asked bool)
}

ConsumeConfig is how a queue's consumer runs: its handler, how long it waits idle, how many messages it handles at once and takes at a time, how it stops, whether it renews a running handler's lease, and when a handler asked to be retried.

type Database

type Database interface {
	// Transact runs fn in a transaction of the database, or in a savepoint
	// of the one ctx carries for it: nil commits or releases, an error
	// rolls back. opts are the transaction's: its isolation level and
	// whether it only reads; a savepoint is given none.
	Transact(ctx context.Context, opts TxOptionsValue, fn func(ctx context.Context) error) error
	// InTransaction reports whether ctx carries a transaction of this
	// database.
	InTransaction(ctx context.Context) bool
	// Defer holds fn until the transaction ctx carries for the database
	// commits, and reports true; outside one it holds nothing and reports
	// false.
	Defer(ctx context.Context, fn func()) bool
	// OnAbort holds fn until the work of the scope ctx carries for the
	// database is undone, and reports true; outside one it holds nothing
	// and reports false.
	OnAbort(ctx context.Context, fn func(ctx context.Context)) bool
}

Database is the framework's scope on one database (ADR 0179 §2): the transactions app.Transact opens on it, their savepoints, and the functions held until their end. The core knows a database only through it; the store package implements it over the SDK's sql. It grows by the siblings below.

type DatabaseConfig

type DatabaseConfig struct {
	// Name is the database's, as the product declared it.
	Name string
	// DB is the pool app.Engine opened.
	DB *sql.DB
	// Dialect is the engine's SQL dialect: "postgres", "mysql" or
	// "sqlite".
	Dialect string
	// Timeout bounds each call the framework makes on the database.
	Timeout time.Duration
	// MaxOpen and MaxIdle bound the pool's connections.
	MaxOpen, MaxIdle int
	// MaxLifetime and MaxIdleTime bound a connection's life.
	MaxLifetime, MaxIdleTime time.Duration
	// CheckTimeout bounds a check of the database.
	CheckTimeout time.Duration
	// Transient is the engine's own reading of a failed transaction — true
	// when the database asks for it to run again —, nil when the engine
	// offers none (app.Classifier). The store subsystem reads the SDK's
	// Classify beside it.
	Transient func(err error) bool
}

DatabaseConfig is one database a product declares, as the framework opened it: its pool, its dialect, its tuning and the timeout of each call.

type DeadLetterManager added in v0.59.0

type DeadLetterManager interface {
	// Replay moves the dead letter id back into the live queue, its
	// attempts counted afresh: its consumer handles it again. found is
	// false when the queue holds no dead letter id.
	Replay(ctx context.Context, id string) (found bool, err error)
	// Drop deletes the dead letter id for good. found is false when the
	// queue holds no dead letter id.
	Drop(ctx context.Context, id string) (found bool, err error)
}

DeadLetterManager is a Broker whose dead letters an operator replays into the live queue or drops for good, from the product's CLI (issue #1138). A sibling of Broker.

type DeadLetterValue

type DeadLetterValue struct {
	// FailedAt is when its last attempt failed.
	FailedAt time.Time
	// Reason is the failure's identifier.
	Reason string
	// Cause is the failure's public text, "" for none.
	Cause string
	// Message is the message, unmodified.
	Message MessageValue
	// Trail is the codes the failure gathered as it was wrapped, oldest
	// first, nil for none.
	Trail []uint32
	// Code is the failure's error code, 0 for none.
	Code uint32
	// Deliveries counts its deliveries.
	Deliveries int
}

DeadLetterValue is a message its queue gave up on: when, why, and how many times it was delivered.

type DeliveryValue

type DeliveryValue struct {
	// Message is what is delivered.
	Message MessageValue
	// Deliveries counts the deliveries, this one included.
	Deliveries int
}

DeliveryValue is one delivery of a message: the message, and how many times it has been delivered, this one included.

type DocumentSink

type DocumentSink interface {
	// PutDocument writes the document key with its versions and its trash
	// as they are given.
	PutDocument(ctx context.Context, key string, versions []VersionValue, trashedAt time.Time) error
	// InsertRaw writes a document of a store that keeps no versions, as it
	// rests.
	InsertRaw(ctx context.Context, raw json.RawMessage) error
}

DocumentSink is a store's documents on the database a data copy writes. A sibling of Documents.

type DocumentSource

type DocumentSource interface {
	// Documents is the document store the engine runs on, and whether there
	// is one.
	Documents() (Documents, bool)
}

DocumentSource is an engine that says the document store it runs on: itself, or the one what it wraps runs on. A data copy reads and writes a store through it (ADR 0178 C7). A sibling of StoreEngine.

type DocumentValue

type DocumentValue struct {
	// JSON is the record as it rests.
	JSON json.RawMessage
	// Value is the entity decoded from JSON, nil until something decoded it;
	// the store's typed facade asserts it to its type.
	Value any
}

DocumentValue is a record as a store's engine holds it (ADR 0179 §2): its JSON as it rests, byte for byte what the framework encodes, and the entity once decoded, kept beside it so that a read, an index or a privacy walk does not decode it twice.

type Documents

type Documents interface {
	// KeyList yields every key the store holds, in key order.
	KeyList(ctx context.Context) iter.Seq2[string, error]
	// TombstoneList is the trash, in key order: none when the store keeps
	// no versions.
	TombstoneList(ctx context.Context) ([]TombstoneValue, error)
	// VersionList is the versions of the document key, newest first.
	VersionList(ctx context.Context, key string) ([]VersionValue, error)
	// Current is the document key as the store keeps it.
	Current(ctx context.Context, key string) (json.RawMessage, error)
	// KeepsVersions reports whether the store keeps versions.
	KeepsVersions() bool
}

Documents is a store's documents as they rest, as a data copy reads them.

type EnterHookSpec

type EnterHookSpec struct {
	// Fn runs the hook; it may change the entity, not its state nor its
	// key.
	Fn func(ctx context.Context, e *WorkflowEntityValue) error
	// State is the state whose entering runs it.
	State string
}

EnterHookSpec is one hook run as an entity enters a state, before it is stored: an error cancels the transition.

type EntrySource

type EntrySource interface {
	// KeyedEntries returns up to limit records as they rest, in key order.
	KeyedEntries(ctx context.Context, limit int) ([]EntryValue, error)
}

EntrySource is an engine that lists its records as they rest with their keys: what a sealing store reads its records by. A sibling of StoreEngine.

type EntryValue

type EntryValue struct {
	// Key is the record's key.
	Key string
	// JSON is the record as it rests.
	JSON json.RawMessage
}

EntryValue is a record as it rests, with its key: what an engine lists for a reader that cannot key a record itself.

type Executor

type Executor interface {
	// ExecContext runs a statement that returns no rows.
	ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error)
	// QueryContext runs a query that returns rows.
	QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error)
	// QueryRowContext runs a query that returns at most one row.
	QueryRowContext(ctx context.Context, query string, args ...any) *sql.Row
}

Executor is what a migration's step runs its statements on: the transaction its migration runs in.

type Folder

type Folder interface {
	// Fold rewrites the store's data with only what it holds now.
	Fold(ctx context.Context) error
}

Folder is an engine that keeps what its writes left beside its data, and can fold it in now. A sibling of StoreEngine.

type HTTPConfig

type HTTPConfig struct {
	// Addr is where to listen, "host:port".
	Addr string
	// Shards is how many sockets the engine opens on Addr.
	Shards int
	// ReadHeader, Read, Write and Idle bound a request's phases.
	ReadHeader, Read, Write, Idle time.Duration
	// MaxHeaderBytes bounds a request's header.
	MaxHeaderBytes int
	// Handler answers every request.
	Handler http.Handler
}

HTTPConfig is what the framework asks of the HTTP engine: where to listen, its one socket, its bounds, and the handler.

type HTTPServer

type HTTPServer interface {
	// Start binds the address and serves, returning once bound.
	Start(ctx context.Context) error
	// State says what the engine binds and serves.
	State() HTTPState
	// Shutdown drains the engine within ctx.
	Shutdown(ctx context.Context) error
}

HTTPServer is the HTTP engine the framework starts, reads and stops.

type HTTPState

type HTTPState struct {
	// Addr is the address the engine bound, "" before it did.
	Addr string
	// Listeners is how many sockets it listens on.
	Listeners int
	// Active are the connections being served, Total those accepted since
	// the start, Rejected those refused.
	Active          int64
	Total, Rejected uint64
}

HTTPState is what the HTTP engine says of itself once it runs: the address it bound, and its connections.

type IndexSpec

type IndexSpec struct {
	// Name reads the index, and names it in a refusal.
	Name string
	// Unique refuses a write that would file two documents under one key.
	Unique bool
	// Keys are a document's keys in the index; an empty key is not indexed.
	Keys func(d DocumentValue) []string
}

IndexSpec declares one secondary index of a store, over documents: the product's index function on its type, wrapped once at the declaration.

type JobDriverConfig

type JobDriverConfig struct {
	// Every is the schedule of a job that runs every period, first one
	// period after the scheduler starts; a period that is not positive is
	// refused.
	Every func(period time.Duration) (JobScheduleFunc, error)
	// Cron is the schedule of a five-field POSIX cron expression, in the
	// process's local time zone; an expression it cannot read is refused.
	Cron func(expr string) (JobScheduleFunc, error)
	// Open opens the scheduler the app's jobs run on, as cfg says, with no
	// entry yet.
	Open func(cfg *JobSchedulerConfig) JobScheduler
}

JobDriverConfig is what framework/app/jobs plugs into kit: how a job's schedule is read from its declaration, and how the scheduler that fires the app's jobs opens.

type JobEntryValue

type JobEntryValue struct {
	// Name names the job; the scheduler refuses a name it holds already.
	Name string
	// Schedule says when the job runs next.
	Schedule JobScheduleFunc
	// Run runs the job once; its error is the result's.
	Run func(ctx context.Context) error
	// Overlap is what a fire does while the job's previous run goes, as the
	// SDK scheduler's OverlapPolicy numbers it: 0 skips it — the zero —, 1
	// runs it beside, 2 replaces the run; the scheduler refuses any other.
	Overlap uint8
	// StartingDeadline bounds how late a fire may still start; zero is no
	// bound.
	StartingDeadline time.Duration
}

JobEntryValue is one job as the scheduler fires it: its name, its schedule, and the run.

type JobResultValue

type JobResultValue struct {
	// Name is the job's.
	Name string
	// Scheduled is the instant the fire was due.
	Scheduled time.Time
	// Started and Finished bound the run; zero for a fire that did not run.
	Started, Finished time.Time
	// Missed counts the fires that came due while the scheduler could not
	// fire them, skipped rather than caught up.
	Missed int
	// Skipped says the fire did not run: a run of the same job was going.
	Skipped bool
	// Expired says the fire did not run: the scheduler came to it more
	// than the job's starting deadline after its instant.
	Expired bool
	// Replaced says a newer fire of a job that replaces its runs cancelled
	// this one — before it started when Started is zero.
	Replaced bool
	// Err is the run's error.
	Err error
}

JobResultValue is one decision of the scheduler: a run of a job, or a fire it skipped.

type JobScheduleFunc

type JobScheduleFunc func(after time.Time) (next time.Time, ok bool)

JobScheduleFunc says when a job runs next after an instant: the instant, and false when it never runs again.

type JobScheduler

type JobScheduler interface {
	// Add registers a job; it is refused while the scheduler runs, for a
	// name it holds already, and for an entry with no name, run or
	// schedule.
	Add(entry JobEntryValue) error
	// Run fires the jobs until ctx ends, then waits for the runs going.
	Run(ctx context.Context) error
}

JobScheduler fires the app's jobs, each on its schedule, on the app's clock: a fire due while the previous run of the same job is going is skipped, a missed one is counted, never caught up.

type JobSchedulerConfig

type JobSchedulerConfig struct {
	// Clock is the app's clock, which the scheduler stamps and waits on.
	Clock Clock
	// OnResult hears every decision of the scheduler — each run, with the
	// job's own error, and each fire skipped or missed —, one at a time.
	OnResult func(res JobResultValue)
}

JobSchedulerConfig is the scheduler the app's jobs run on: the app's clock and what the framework hears of each fire.

type Keyser

type Keyser interface {
	// Keys yields the keys above after, in order, then its failure if any.
	Keys(ctx context.Context, after string) iter.Seq2[string, error]
}

Keyser is an engine that lists the keys of its documents, in key order, above after, without reading a document. A sibling of StoreEngine.

type LaterPublisher added in v0.50.0

type LaterPublisher interface {
	// PublishAt puts payload in the queue, received by no consumer before
	// at: in the transaction ctx carries for its database, when it lives on
	// one.
	PublishAt(ctx context.Context, payload []byte, at time.Time) error
	// PublishOnce puts payload in the queue unless a publication under key
	// was made within window, and reports whether it did.
	PublishOnce(ctx context.Context, key string, payload []byte, window time.Duration) (published bool, err error)
}

LaterPublisher is a Broker that publishes a message for later, and once per key. A sibling of Broker.

type LiveMessageValue

type LiveMessageValue struct {
	// VisibleAt is when the message is next delivered.
	VisibleAt time.Time
	// Message is the message.
	Message MessageValue
	// Deliveries counts its deliveries so far.
	Deliveries int
	// Leased reports whether a consumer holds it.
	Leased bool
}

LiveMessageValue is a message waiting in its queue, as it lies: when it is next visible, how many times it was delivered, and whether a consumer holds it.

type MailAttemptValue

type MailAttemptValue struct {
	// QueuedAt is when the mail was put in the outbox.
	QueuedAt time.Time
	// Meta is what Annotate kept of the Send.
	Meta map[string]string
	// ID is the mail's outbox ID.
	ID string
	// Attempt numbers the attempt, from 1.
	Attempt int
}

MailAttemptValue is one delivery attempt of a mail: its outbox ID, its number, when the mail was queued, and what the spool kept of its Send.

type MailCaptureSource

type MailCaptureSource interface {
	// Composed is the last message the transport composed, nil for none.
	Composed() []byte
}

MailCaptureSource is a transport that keeps what it composed: the capture transport, whose last message the Studio's mailbox shows. A sibling of MailSink.

type MailDeadLetterValue added in v0.53.0

type MailDeadLetterValue struct {
	// Meta is what Annotate kept of the Send.
	Meta map[string]string
	// FailedAt is when its last attempt failed.
	FailedAt time.Time
	// QueuedAt is when the mail was put in the outbox.
	QueuedAt time.Time
	// Message is the mail.
	Message MailValue
	// ID is the mail's outbox ID; empty when its record did not decode, and
	// QueueID then names it.
	ID string
	// QueueID is the outbox queue's identifier for its record.
	QueueID string
	// Cause is its last failure's public text, "" for none.
	Cause string
	// Attempts counts its delivery attempts.
	Attempts int
	// GivenUp is why it was given up, read from its last failure's code and
	// trail as the outbox kept them.
	GivenUp MailGiveUp
}

MailDeadLetterValue is a mail an outbox gave up on, read back from its dead letters: what the mailbox of a later run shows of it, why it was given up included.

type MailDriverConfig

type MailDriverConfig struct {
	// Open opens one mailer's outbox as cfg says, closed until it runs.
	Open func(cfg *MailSpoolConfig) (MailSpool, error)
	// Validate is the SDK's verdict on a mail: nil when the outbox takes it,
	// else what is wrong with it, in the SDK's public words.
	Validate func(msg MailValue) error
	// Capture is a transport that delivers nothing and keeps the last
	// message it composed (MailCaptureSource).
	Capture func() MailSink
	// ParseSMTP reads an SMTP URL — smtp://user:password@host:port?tls=
	// starttls|implicit|none, smtps:// for implicit TLS — as the SDK's
	// SMTP transport would take it.
	ParseSMTP func(url string) (MailRelayValue, error)
	// NewSMTP is the SDK's SMTP transport to relay, which dials nothing
	// until a mail is sent.
	NewSMTP func(relay *MailRelayValue) (MailSink, error)
	// Refused reports whether err, or an error it wraps, is the spool's or
	// the URL's refusal of kind: the SDK's sentinels stay in the subsystem,
	// and the error keeps the fields the SDK gave it.
	Refused func(err error, kind MailRefusal) bool
}

MailDriverConfig is what framework/app/mail plugs into kit: how a mailer's outbox opens, the SDK's verdict on a mail, the transports a mailer hands its mail to, and how the framework tells the spool's refusals apart.

type MailEvent

type MailEvent uint8

MailEvent is what a spool reports of a mail.

const (
	// MailEventOther is an event of the spool the framework shows nothing of.
	MailEventOther MailEvent = iota
	// MailEventQueued is a mail put in the outbox.
	MailEventQueued
	// MailEventSent is a mail the transport accepted.
	MailEventSent
	// MailEventRetrying is a failed attempt that will be retried.
	MailEventRetrying
	// MailEventDeadLettered is a mail given up on after its last attempt.
	MailEventDeadLettered
	// MailEventDuplicate is a redelivery of a mail already sent, dropped.
	MailEventDuplicate
)

What a spool reports of a mail.

type MailEventValue

type MailEventValue struct {
	// Err is a failed attempt's failure.
	Err error
	// Reply is the SMTP reply the failure carries, nil for none: the
	// receiving server's own words, never shown in a public message.
	Reply *textproto.Error
	// Meta is what Annotate kept of the Send.
	Meta map[string]string
	// At is when the event happened.
	At time.Time
	// QueuedAt is when the mail was put in the outbox.
	QueuedAt time.Time
	// Message is the mail.
	Message MailValue
	// ID is the mail's outbox ID.
	ID string
	// Attempt numbers the attempt the event is about.
	Attempt int
	// Kind is what happened.
	Kind MailEvent
	// GivenUp is why a dead letter was given up, for MailEventDeadLettered.
	GivenUp MailGiveUp
}

MailEventValue is what a spool reports of a mail: its kind, the mail and its outbox ID, the attempt, when, the failure of a failed attempt, and why a dead letter was given up.

type MailGiveUp added in v0.47.0

type MailGiveUp uint8

MailGiveUp is why a spool gave a mail up.

const (
	// MailGivenUpExhausted is a mail whose last attempt failed.
	MailGivenUpExhausted MailGiveUp = iota
	// MailGivenUpRejected is a mail the receiving server refused for good,
	// an SMTP 5xx reply, dead-lettered without a retry.
	MailGivenUpRejected
	// MailGivenUpExpired is a mail whose attempt failed once it was older
	// than the spool's MaxAge.
	MailGivenUpExpired
)

Why a spool gave a mail up: what the framework tells the product's bounce hook and the Studio's mailbox of a dead letter.

type MailRefusal

type MailRefusal uint8

MailRefusal is a refusal of the mail subsystem, as the framework words it.

const (
	// MailRefusalNone is no refusal the framework words.
	MailRefusalNone MailRefusal = iota
	// MailRefusalClosed is a spool that is closed: its mailer is not
	// running.
	MailRefusalClosed
	// MailRefusalUnencodable is a mail the outbox cannot encode.
	MailRefusalUnencodable
	// MailRefusalInvalidURL is an SMTP URL that is not one of the form
	// smtp://user:password@host:port; its "problem" field says the clause.
	MailRefusalInvalidURL
)

The spool's refusals the framework tells apart, which it words for the product.

type MailRelayValue

type MailRelayValue struct {
	// Config is the SDK's SMTP configuration, held as any.
	Config any
	// Server is where it delivers, host:port.
	Server string
	// TLS is its TLS mode as the URL spells it: starttls, implicit or none.
	TLS string
}

MailRelayValue is an SMTP relay as the SDK's transport takes it: its configuration, which holds the password and is handed to NewSMTP and never kept or printed, and what may be shown of it.

type MailSink

type MailSink interface {
	// Send delivers msg.
	Send(ctx context.Context, msg MailValue) error
}

MailSink is what a mailer hands a mail to: the SDK's SMTP transport, or its capture transport, which delivers nothing. It grows by the sibling below.

type MailSpool

type MailSpool interface {
	// Send puts msg in the outbox — in the transaction ctx carries for its
	// database, when it lives on one — and returns its outbox ID.
	Send(ctx context.Context, msg MailValue) (string, error)
	// SendWithID puts msg in the outbox under id, minted by the framework.
	SendWithID(ctx context.Context, id string, msg MailValue) error
	// DeadLetters returns up to maxLetters of the mails earlier runs gave up
	// on, oldest first, each with why.
	DeadLetters(ctx context.Context, maxLetters int) ([]MailDeadLetterValue, error)
	// Run hands each mail to the transport until ctx ends.
	Run(ctx context.Context) error
	// Close releases the outbox.
	Close() error
}

MailSpool is one mailer's outbox as the framework's core uses it: a mail put in it at once or under an ID the framework minted, the loop that hands each mail to the transport, and its dead letters.

type MailSpoolConfig

type MailSpoolConfig struct {
	// Transport makes one delivery attempt of msg; the spool retries a
	// failure, or dead-letters the mail after its last attempt.
	Transport func(ctx context.Context, msg MailValue, attempt MailAttemptValue) error
	// Clock is the app's clock, which the spool stamps and waits on.
	Clock Clock
	// Observe is told each event of each mail.
	Observe func(e *MailEventValue)
	// Annotate is what the spool keeps of a Send for its deliveries, read
	// from the Send's context.
	Annotate func(ctx context.Context) map[string]string
	// NewID mints a mail's outbox ID.
	NewID func() (string, error)
	// Outbox is the queue the spool keeps its mails in on a database —
	// the queue subsystem's, sealed —, nil for a directory or memory.
	Outbox Broker
	// Database is the database Outbox is on, whose transaction a mail sent
	// in one joins; nil for none.
	Database Database
	// From is the sender of every mail that names none: the SDK's
	// mail.Address, held as any.
	From MailValue
	// Dir is the directory the spool keeps its own queue in; with no Outbox
	// and no Dir, the outbox is in memory.
	Dir string
	// BackoffBase is the wait after a failed attempt, doubled after each,
	// up to BackoffMax.
	BackoffBase time.Duration
	// BackoffMax bounds the wait after a failed attempt.
	BackoffMax time.Duration
	// SendTimeout bounds one attempt.
	SendTimeout time.Duration
	// PollInterval bounds an idle wait.
	PollInterval time.Duration
	// MaxAttempts is how many attempts a mail gets before it is
	// dead-lettered.
	MaxAttempts int
	// MaxMessageBytes bounds one mail in the spool's own queue; zero is the
	// spool's own bound.
	MaxMessageBytes int
	// MaxAge is how long after it was queued a mail may still be retried:
	// an attempt that fails later gives it up; zero sets no age.
	MaxAge time.Duration
	// RetryPermanent retries a mail the receiving server refused for good —
	// an SMTP 5xx reply — like a temporary failure, instead of giving it up
	// at once.
	RetryPermanent bool
}

MailSpoolConfig is one mailer's outbox: the transport each attempt runs, the app's clock, what the framework hears of its mails, its retries, and where it keeps them — a queue on the database that keeps the mailer's service, a directory, or memory.

type MailValue

type MailValue struct {
	// Value is the SDK's mail value.
	Value any
}

MailValue is a value of the SDK's mail package as it crosses the contract: a mail.Message, or a sender's mail.Address, held as any — the framework's core names the SDK's mail types, plug names none.

type MessageMover

type MessageMover interface {
	// Messages are up to maxMessages live messages after the identifier
	// after, "" for the first, in their queue's order.
	Messages(ctx context.Context, after string, maxMessages int) ([]LiveMessageValue, error)
	// PutMessage writes live under an identifier of the queue's own, and
	// returns it.
	PutMessage(ctx context.Context, live LiveMessageValue) (string, error)
	// PutDeadLetter writes dead, with its cause, under an identifier of the
	// queue's own, and returns it.
	PutDeadLetter(ctx context.Context, dead DeadLetterValue) (string, error)
}

MessageMover is a Broker whose messages a data copy reads and writes as they lie, without a lease, with their counts and their instants. A sibling of Broker.

type MessageValue

type MessageValue struct {
	// EnqueuedAt is when the message was published.
	EnqueuedAt time.Time
	// ID identifies the message in its queue.
	ID string
	// Payload is the message as the framework encoded it.
	Payload []byte
}

MessageValue is one message of a queue: its identifier, its payload as the framework encoded it, and when it was published.

type MigrationValue

type MigrationValue struct {
	// Version orders the migration in its set: non-zero and unique.
	Version uint64
	// Name labels it in the version table.
	Name string
	// Up applies the change.
	Up Step
	// Down reverses it.
	Down Step
}

MigrationValue is one versioned change of a database's schema and its reversal, as the core hands it to the store subsystem: a product's app.Migration, or one of the framework's own, its steps on the standard library's types.

type Migrator

type Migrator interface {
	// Plan is the set's pending migrations, oldest first, applying nothing.
	Plan(ctx context.Context) ([]MigrationValue, error)
	// Up applies every pending migration, in order.
	Up(ctx context.Context) error
	// Down reverses the applied migrations above version, newest first.
	Down(ctx context.Context, version uint64) error
}

Migrator is one set of migrations on a database.

type MigratorProvider

type MigratorProvider interface {
	// Migrator is the set ms, under the version table table.
	Migrator(table string, ms []MigrationValue) (Migrator, error)
}

MigratorProvider is a Database that runs a set of migrations under a version table of its own, and so a lock of its own. A sibling of Database.

type OTLPBatchValue added in v0.52.0

type OTLPBatchValue struct {
	// Signal is OTLPTraces or OTLPMetrics.
	Signal string
	// Document is the OTLP/JSON export request.
	Document []byte
}

OTLPBatchValue is one batch as the product's own sender receives it: its signal and its OTLP/JSON document, posted to a collector as it is.

type OTLPConfig added in v0.52.0

type OTLPConfig struct {
	// Clock is the app's clock: the queues stamp and age a batch on it, the
	// retries and each attempt's bound wait on it, the metrics are
	// collected on it.
	Clock Clock
	// Headers ride on every request to the collector — an Authorization, a
	// tenant —; they are the secret otlp-headers, never shown.
	Headers map[string]string
	// Send, when set, ships a batch in place of the OTLP/HTTP exporters:
	// the product's own sender. Retryable then classifies its failures.
	Send func(ctx context.Context, batch OTLPBatchValue) error
	// Retryable classifies a failure of Send: a later attempt may cure it.
	// Unused without Send: the OTLP/HTTP exporters classify their own.
	Retryable func(err error) bool
	// OnError hears what the export could not keep — a batch of spans or a
	// snapshot its queue refused — and what it could not close; the core
	// logs it. The forwarder counts every batch it loses on its own.
	OnError func(err error)
	// Service and Version name the producer: the resource's service.name
	// and the instrumentation scope's version.
	Service, Version string
	// Endpoint is the collector's base URL, "http://collector:4318": each
	// signal's path is appended to it. Unused with Send.
	Endpoint string
	// Dir is the directory the two queues lie in, one subdirectory per
	// signal; "" keeps them in memory, lost at a stop. Unused with Database.
	Dir string
	// Database keeps the two queues, one table each (Tables), nil when Dir
	// or memory does: a scope the store subsystem's Database opened, on
	// which the queue subsystem opens the SDK's SQL broker (OpenSDK).
	Database Database
	// Tables are the queues' tables on Database, by signal.
	Tables map[string]string
	// WhenFull is what a full queue does with a new batch: OTLPDropOldest,
	// OTLPDropNewest or OTLPBlock.
	WhenFull string
	// MaxBytes bounds the bytes each queue holds.
	MaxBytes int64
	// MaxBatches bounds the batches each queue holds.
	MaxBatches int
	// MaxAge is how long after it was queued a batch may still be sent.
	MaxAge time.Duration
	// SendTimeout bounds one attempt, and the hand-over of the spans the
	// batch sink exports to their queue.
	SendTimeout time.Duration
	// Interval is how often the metrics are collected and queued.
	Interval time.Duration
	// DrainTimeout is how long the batch being sent at a stop may still
	// run; SettleTimeout bounds each acknowledgement once the stop began,
	// and the flush of what the export still holds in memory.
	DrainTimeout, SettleTimeout time.Duration
}

OTLPConfig is what the framework asks of an export: who produces the telemetry, where it goes, where it waits, its bounds and the app's clock.

type OTLPDeadLetterValue added in v0.56.0

type OTLPDeadLetterValue struct {
	// FailedAt is when its last attempt failed.
	FailedAt time.Time
	// ID identifies it in its queue: what replay and drop take.
	ID string
	// Reason is the failure's identifier.
	Reason string
	// Cause is the failure's public text, "" for none.
	Cause string
	// Trail is the codes the failure gathered as it was wrapped, oldest
	// first, nil for none.
	Trail []uint32
	// Code is the failure's error code, 0 for none.
	Code uint32
	// Deliveries counts its attempts.
	Deliveries int
	// Size is its payload's bytes.
	Size int
}

OTLPDeadLetterValue is one batch a signal's queue gave up on — the collector refused it for good —, as the product's CLI lists it: never its payload.

type OTLPDriverConfig added in v0.52.0

type OTLPDriverConfig struct {
	// Open opens the export cfg describes: its two queues — read, the
	// backlog a previous process left counted —, its senders and its
	// meter. It sends nothing until OTLPExporter.Run.
	Open func(ctx context.Context, cfg *OTLPConfig) (OTLPExporter, error)
	// Queue opens one signal's queue as Open keeps it — the same directory
	// or table, the same policy — for the product's CLI, which lists and
	// replays its dead letters (issue #536); it is refused when the queue
	// would be in memory, where no dead letter outlives its process.
	Queue func(ctx context.Context, cfg *OTLPConfig, signal string) (OTLPQueue, error)
	// Policy is the policy Open and Queue open each signal's queue under
	// for cfg — its lease, its deliveries, its largest message —, for
	// the product's CLI, which opens the same queues through the queue
	// subsystem to move them onto a database (otlp migrate, issue #586).
	Policy func(cfg *OTLPConfig) QueuePolicyValue
}

OTLPDriverConfig is what framework/app/otlp plugs into the framework: how an app's export opens.

type OTLPExporter added in v0.52.0

type OTLPExporter interface {
	// SpanSink is the sink the app's tracer ends its spans into.
	SpanSink() OTLPSinkValue
	// Meter is the product's own meter, collected at each interval beside
	// the framework's, into the same metrics queue, under the same resource
	// and a scope named after the product.
	Meter() OTLPMeterValue
	// Record counts one unit of work the framework observed on node: its
	// operation, how long it took, and whether it failed.
	Record(node, op string, took time.Duration, failed bool)
	// Run sends the queued batches and collects the metrics until ctx ends;
	// then it flushes what it holds in memory into the queues, lets the
	// batch being sent finish within the drain, and closes the queues.
	Run(ctx context.Context) error
	// Stats is what each signal's queue holds, has sent and has lost.
	Stats() []OTLPStatsValue
}

OTLPExporter is an app's export, open: where the tracer hands its spans, what the framework records of each unit of work, the loop that sends, and what it counts.

type OTLPMeterValue added in v0.54.0

type OTLPMeterValue struct {
	// Meter is the SDK's metrics.FullMeter.
	Meter any
}

OTLPMeterValue is the product's own meter on the export: the SDK's metrics.FullMeter held as any, as OTLPSinkValue holds the span sink.

type OTLPQueue added in v0.56.0

type OTLPQueue interface {
	// DeadLetters are at most max of the batches the queue gave up on,
	// oldest first.
	DeadLetters(ctx context.Context, max int) ([]OTLPDeadLetterValue, error)
	// Replay moves the dead letter id back into the live queue, its
	// attempts counted afresh: the export sends it again. found is false
	// when the queue holds no dead letter id.
	Replay(ctx context.Context, id string) (found bool, err error)
	// Drop deletes the dead letter id for good. found is false when the
	// queue holds no dead letter id.
	Drop(ctx context.Context, id string) (found bool, err error)
	// Close releases what the queue holds.
	Close() error
}

OTLPQueue is one signal's queue of the export as the product's CLI opens it (issue #536): its dead letters read, replayed into the live queue, or dropped.

type OTLPSinkValue added in v0.52.0

type OTLPSinkValue struct {
	// Sink is the SDK's trace.SpanSink.
	Sink any
}

OTLPSinkValue is the export's span sink: the SDK's trace.SpanSink held as any, as a MailValue holds a mail — plug names no SDK type, and the core, which names the SDK's trace, takes it back.

type OTLPStatsValue added in v0.52.0

type OTLPStatsValue struct {
	// LastRetryAfterAt is when the collector last imposed a delay; zero
	// when it never did.
	LastRetryAfterAt time.Time
	// Signal is OTLPTraces or OTLPMetrics.
	Signal string
	// PendingBytes and MaxBytes are the bytes the queue holds and may hold.
	PendingBytes, MaxBytes int64
	// LastRetryAfter is the last delay the collector imposed.
	LastRetryAfter time.Duration
	// Pending and MaxBatches are the batches the queue holds and may hold.
	Pending, MaxBatches int
	// Enqueued, Sent and Retries count the batches kept, sent and the
	// attempts made again.
	Enqueued, Sent, Retries uint64
	// Dropped, Expired and DeadLettered count the batches lost to a bound,
	// to their age and to a permanent refusal.
	Dropped, Expired, DeadLettered uint64
	// Durable reports whether the queue outlives the process: false in
	// memory — no directory, or a platform whose durable queue the SDK
	// refuses.
	Durable bool
}

OTLPStatsValue is what one signal's queue holds, has sent and has lost, with its bounds.

type QueueConfig

type QueueConfig struct {
	// Name names the queue's node in a refusal: the consumer's or the
	// mailer's node ID.
	Name string
	// Dir is the directory a file queue lies in; with no Database and no
	// Dir, the queue is in memory.
	Dir string
	// Database keeps the queue, nil when Dir or memory does: a scope the
	// store subsystem's Database opened, whose transaction a publication in
	// it joins.
	Database Database
	// Table is the queue's table on Database.
	Table string
	// Policy is how the queue leases, retries and bounds its messages.
	Policy QueuePolicyValue
	// Clock is the app's clock, which the queue stamps and waits on.
	Clock Clock
	// Seal, when set, seals every payload on its way in — a mail's, in a
	// mailer's outbox on a database —, and Unseal opens one on its way out;
	// MaxPayload bounds a payload before it is sealed.
	Seal func(ctx context.Context, payload []byte) ([]byte, error)
	// Unseal is the payload a box holds, the box as it lies when it does
	// not open.
	Unseal func(ctx context.Context, box []byte) []byte
	// MaxPayload bounds a payload Seal seals.
	MaxPayload int
	// Wrap, when a test sets it, stands in front of the queue the subsystem
	// opens: a func(queue.Broker) queue.Broker of the SDK's queue, which
	// the framework's core does not name. Nil in every app a product builds.
	Wrap any
}

QueueConfig is what the framework asks of one queue: where it lies, its policy, the app's clock, and for a mailer's outbox the sealing of what it keeps.

type QueueDriverConfig

type QueueDriverConfig struct {
	// Open opens one queue, as cfg places it: on a database, in a
	// directory, or in memory.
	Open func(cfg QueueConfig) (Broker, error)
	// OpenSDK opens one queue as cfg places it, and hands the SDK's
	// queue.Broker itself, held as any: for a subsystem that drives the
	// SDK's queue on its own — the OTLP export's forwarder (issue #537) —,
	// with no consumer, no sealing and no test's wrapper.
	OpenSDK func(cfg QueueConfig) (any, error)
	// TableMigration is the migration that makes the queue table on a
	// database of the dialect named, at version.
	TableMigration func(dialect, table string, version uint64) (MigrationValue, error)
	// TrailMigration is the migration that adds the column a dead letter's
	// trail is kept in to a queue table an earlier release made on a
	// database of the dialect named, at version; it does nothing on a table
	// that has it, or that is not there yet.
	TrailMigration func(dialect, table string, version uint64) (MigrationValue, error)
	// DoNotRetry is err as a delivery's handler returns it when no retry
	// can help: its queue dead-letters the message at once.
	DoNotRetry func(err error) error
	// NotRetryable reports whether err, a delivery's handler's, says that no
	// retry can help: what DoNotRetry returned, the product's own included.
	NotRetryable func(err error) bool
}

QueueDriverConfig is what framework/app/queue plugs into kit: how a consumer's queue opens, the migrations that make its table on a database and add the column its dead letters' trails are kept in, and how a delivery's handler says that no retry can help.

type QueuePolicyValue

type QueuePolicyValue struct {
	// VisibilityTimeout is how long a delivery is leased.
	VisibilityTimeout time.Duration
	// RetryDelay is the wait after a message's first failure, doubled after
	// each, up to MaxRetryDelay.
	RetryDelay time.Duration
	// MaxRetryDelay bounds the wait before a retry; zero leaves it unbound.
	MaxRetryDelay time.Duration
	// MaxDeliveries is how often a message is delivered before it is
	// dead-lettered.
	MaxDeliveries int
	// MaxMessageBytes bounds a message; zero is the queue's own bound.
	MaxMessageBytes int
}

QueuePolicyValue is how a queue leases, retries and bounds its messages: the SDK's queue policy, in the framework's terms.

type Refusal

type Refusal uint8

Refusal is a kind of refusal of a store's engine or a database, as the framework words it.

const (
	// RefusalNone is no refusal the framework words.
	RefusalNone Refusal = iota
	// RefusalNotFound is no document under the key, or under the index's
	// key.
	RefusalNotFound
	// RefusalExists is a document already under the key an insertion names.
	RefusalExists
	// RefusalUniqueTaken is another document under a unique index's key.
	RefusalUniqueTaken
	// RefusalKeyEmpty is a document whose key is empty.
	RefusalKeyEmpty
	// RefusalKeyChanged is an update that changes the document's key.
	RefusalKeyChanged
	// RefusalIndexUnknown is an index the store does not declare.
	RefusalIndexUnknown
	// RefusalIndexNotUnique is a lookup on an index that is not unique.
	RefusalIndexNotUnique
	// RefusalIndexBroken is stored documents that break a unique index.
	RefusalIndexBroken
	// RefusalUndecodable is a record that does not decode into its type.
	RefusalUndecodable
	// RefusalUnencodable is an entity that does not encode.
	RefusalUnencodable
	// RefusalPersist is a write the store could not keep.
	RefusalPersist
	// RefusalLoad is a store that could not be loaded; its "problem" field
	// says why.
	RefusalLoad
	// RefusalClosed is a call on a closed engine.
	RefusalClosed
	// RefusalUnconfirmed is a write that stands but whose survival across a
	// power loss is in doubt.
	RefusalUnconfirmed
	// RefusalVersionsNotKept is a call on the versions of a store that keeps
	// none.
	RefusalVersionsNotKept
	// RefusalVersionsRewrite is a rewrite of versions that adds or
	// renumbers one.
	RefusalVersionsRewrite
	// RefusalNotTrashed is no record in the trash under the key.
	RefusalNotTrashed
	// RefusalKeyTooLong is a key longer than a database's key columns hold;
	// its "max" field says how long they hold.
	RefusalKeyTooLong
	// RefusalStatement is a statement the database did not complete.
	RefusalStatement
	// RefusalTxClosed is a call with the context of a transaction that
	// ended.
	RefusalTxClosed
	// RefusalTxFailed is a transaction or a savepoint the database would
	// not open, commit or roll back.
	RefusalTxFailed
	// RefusalOutOfOrder is a migration older than one already applied; its
	// "applied" field names the newer.
	RefusalOutOfOrder
	// RefusalRenameTarget is a table whose present name is taken while its
	// former one still holds the framework's data (ADR 0180 step 5); its
	// "tables" field names them, and nothing was moved.
	RefusalRenameTarget
)

The kinds of refusal.

type RefusalError

type RefusalError struct {
	// Err is what the engine met.
	Err error
	// Kind is how the framework words it.
	Kind Refusal
}

RefusalError is an engine's refusal of one kind: the error it met, and the kind the framework words it by.

func (*RefusalError) Error

func (e *RefusalError) Error() string

Error is what the engine met's.

func (*RefusalError) Unwrap

func (e *RefusalError) Unwrap() error

Unwrap is what the engine met.

type Reindexer

type Reindexer interface {
	// Reindex files every record's index rows again.
	Reindex(ctx context.Context) error
}

Reindexer is an engine on a database that files its index rows again. A sibling of StoreEngine.

type RenameSpec added in v0.41.0

type RenameSpec struct {
	// FormerVersions is the version table the framework's set had: the move
	// holds its migration lock, is recorded there, and drops it once the
	// history is the present table's.
	FormerVersions string
	// Versions is the version table the framework's set has now.
	Versions string
	// Name labels the move in FormerVersions, at Version.
	Name string
	// Tables are the tables moved, each from its former name to its present
	// one.
	Tables []RenameValue
	// Labels are the names of the tables' migrations in the history, each
	// from what the former release recorded to what this one says.
	Labels []RenameValue
	// Version is the move's version in FormerVersions: above every version
	// the framework gives.
	Version uint64
}

RenameSpec is the framework's tables on a database moved to their present names (ADR 0180 step 5): each table — with the tables the document store derives from it, <table>___ix and <table>___vs —, the history of the former version table taken by the present one, and the names that history gives the tables' migrations.

type RenameValue added in v0.41.0

type RenameValue struct {
	// From is the former name.
	From string
	// To is the present one.
	To string
}

RenameValue is one name replaced by another: a table's, or a migration's name in a version table.

type StampValue

type StampValue struct {
	// Meta is kept with the version the write makes.
	Meta map[string]string
	// InPlace makes the write change the document without making a version.
	InPlace bool
}

StampValue is what a write says about the version it makes: who made it and which command, kept with the version; and whether it changes the document in place, without a version of its own.

type Step

type Step func(ctx context.Context, ex Executor) error

Step is one direction of a migration, run on ex.

type StoreConfig

type StoreConfig struct {
	// Name is the store's, as a log line and a rollback name it.
	Name string
	// Key is a document's key: the product's key function on its type,
	// wrapped once at the declaration. It reads the document's Value, which
	// the engine decodes first unless KeyAtRest gives the key.
	Key func(d DocumentValue) string
	// KeyAtRest, when set, gives the key of a record as it rests, without
	// decoding it; false when it cannot.
	KeyAtRest func(raw json.RawMessage) (string, bool)
	// Decode is the entity a document's JSON holds, which the engine keeps
	// as the document's Value.
	Decode func(raw json.RawMessage) (any, error)
	// Indexes are the store's secondary indexes.
	Indexes []IndexSpec
	// Data is the data directory the store rests in — the SDK's writable
	// file system, which the engine asserts — and Path its snapshot there;
	// a nil Data and a nil Database keep the store in memory.
	Data fs.FS
	// Path is the store's snapshot in Data.
	Path string
	// Database keeps the store, nil when the data directory or memory does:
	// a scope the store subsystem's Database opened.
	Database Database
	// Table is the store's table on Database.
	Table string
	// IndexKey is the key a table's index keys are hashed under, nil for
	// none: an index key reaches the table as its keyed hash.
	IndexKey func(index, key string) []byte
	// Call is the context one call of the engine on Database runs with: on
	// the transaction ctx carries for it, else on the pool, within the
	// database's timeout; done ends it.
	Call func(ctx context.Context, write bool) (call context.Context, done func(), err error)
	// Versions is how many former versions of each record the engine keeps,
	// none when zero; Clock stamps them.
	Versions int
	// Clock is the app's clock, which stamps a version.
	Clock func() time.Time
	// Held reports whether a record's versions are held, and no write may
	// prune them: asked with the write's context, on a database inside its
	// transaction.
	Held func(ctx context.Context, key string) bool
	// Stamp is what a write under ctx says about the version it makes.
	Stamp func(ctx context.Context) StampValue
	// Transaction is the framework's transaction, which the engine's writes take part
	// in.
	Transaction Transaction
}

StoreConfig is what the framework asks of one store's engine: the store, its key and its indexes over documents, where it rests and what it keeps, and how its writes take part in the framework's transactions.

type StoreDriverConfig

type StoreDriverConfig struct {
	// Open opens the engine of one store, as cfg places it: loaded from the
	// data directory, empty in memory, or on a database.
	Open func(cfg StoreConfig) (StoreEngine, error)
	// Database opens the framework's scope on one database's pool.
	Database func(cfg DatabaseConfig) (Database, error)
	// TableMigration is the migration that makes the table t on a database
	// of the dialect named, at version.
	TableMigration func(dialect string, t TableSpec, version uint64) (MigrationValue, error)
	// FormerTables are the tables of plan still under a former name on db —
	// its former version table among them —, read from the database's
	// catalogue, sorted: what RenameTables would move; none once moved.
	FormerTables func(ctx context.Context, db Database, plan RenameSpec) ([]string, error)
	// RenameTables moves the tables of plan to their present names on db
	// (ADR 0180 step 5), under the migration lock of plan's former version
	// table and in the transaction that records the move there, and returns
	// the tables it moved; none when nothing was left under a former name.
	// A table whose present name is taken too is a [RefusalRenameTarget],
	// and nothing moves.
	RenameTables func(ctx context.Context, db Database, plan RenameSpec) ([]string, error)
}

StoreDriverConfig is what framework/app/store plugs into kit: how a store's engine opens, how the framework opens its scope on a database, and the migration that makes one of the framework's tables.

type StoreEngine

type StoreEngine interface {
	// Get returns the document under key.
	Get(ctx context.Context, key string) (DocumentValue, error)
	// List returns every document, in key order.
	List(ctx context.Context) ([]DocumentValue, error)
	// Filter returns the documents keep accepts, in key order.
	Filter(ctx context.Context, keep func(d DocumentValue) bool) ([]DocumentValue, error)
	// Lookup returns the document a unique index files under key.
	Lookup(ctx context.Context, index, key string) (DocumentValue, error)
	// Find returns the documents an index files under key, in key order.
	Find(ctx context.Context, index, key string) ([]DocumentValue, error)
	// Count says how many documents the store holds.
	Count(ctx context.Context) (int, error)
	// Entries returns up to limit documents as they rest, in key order.
	Entries(ctx context.Context, limit int) ([]json.RawMessage, error)
	// Write stores d as mode says. The document and its index keys are kept
	// together, or neither.
	Write(ctx context.Context, d DocumentValue, mode WriteMode) error
	// Update applies fn to the document under key and stores the result,
	// atomically with respect to every other write of the store.
	Update(ctx context.Context, key string, fn func(d *DocumentValue) error) (DocumentValue, error)
	// Delete removes the document under key.
	Delete(ctx context.Context, key string) error
	// Watch registers the functions told the key of every document written
	// and deleted, once the write stands.
	Watch(onWrite, onDelete func(key string))
	// Close releases the engine.
	Close() error
}

StoreEngine is what a store runs on, over documents (ADR 0179 §2): the non-generic engine under Store[T]. Its refusals are the framework's (Refusal): the engine translates the SDK's before they reach the core. Every call takes the caller's context, which carries the transaction the call joins. It grows by the sibling interfaces below, never by a method (the SDK's ADR 0039).

type StudioDriverConfig

type StudioDriverConfig struct {
	// Env reads what the tool's variables ask of the Studio in this run.
	Env func(getenv func(string) string) StudioEnvValue
	// Settings are the tool's variables as the settings of a run show them,
	// in order, each with its value as the run resolved it and where it
	// came from: the product's code, the environment, or the framework's default.
	Settings func(getenv func(string) string, state StudioStateValue) []model.Setting
	// Forced are the variables kit dev says it set itself for this launch,
	// as it names them; the framework labels only those it lets kit dev set.
	Forced func(getenv func(string) string) []string
	// DevBuild is what kit dev said about the build it launched, nil when
	// the process was not started by kit dev.
	DevBuild func(getenv func(string) string) *model.DevBuild
	// Mount registers the Studio's routes on mux, each behind the Studio's
	// guard, reading the running app through host.
	Mount func(mux *http.ServeMux, host StudioHost)
}

StudioDriverConfig is what framework/app/studio plugs into kit: how the tool's variables are read, and how the Studio's routes mount.

type StudioEnvValue

type StudioEnvValue struct {
	// Studio is what the environment says of the Studio: on — which
	// production refuses —, off, or empty when it says neither.
	Studio string
	// Remote: the Studio answers a client that is not on this machine.
	Remote bool
	// NoAnalysis: the environment turns the static analysis off.
	NoAnalysis bool
}

StudioEnvValue is what the tool's variables ask of the Studio: their zero value is a run in which none is set.

type StudioHost

type StudioHost interface {
	// Graph is the app's graph, as it is now.
	Graph() *model.Graph
	// Phase is where the app is in its life, as the graph says it.
	Phase() string
	// Now is the time on the app's clock.
	Now() time.Time
	// Subscribe streams the app's live events until cancel is called.
	Subscribe() (events <-chan model.Event, cancel func())
	// Stopping is closed when the app ends its live streams.
	Stopping() <-chan struct{}
	// Traces are the latest traces the app keeps, at most limit, those of
	// root's trace or through node when either is given.
	Traces(limit int, root, node string) []model.Trace
	// Trace is one trace, while the app keeps it.
	Trace(id string) (model.Trace, bool)
	// Logs are the latest records the product logged, those of a trace or
	// a node and from a level when given, at most limit — a default when
	// it is empty; a level or a limit the app does not take is refused.
	Logs(trace, node, level, limit string) ([]model.LogRecord, error)
	// Instances are a workflow's entities and where each is; false for no
	// such workflow.
	Instances(workflow string) ([]model.Instance, bool)
	// Items are a store's latest entities, redacted as payloads are; false
	// for no such store.
	Items(store string) ([]json.RawMessage, bool)
	// Source is a file the graph names, of the product's Go module or of
	// the one module names: a regular file within the bound, never a link;
	// false for any other name.
	Source(ctx context.Context, module, file string) ([]byte, bool)
	// Locate says where the function fn, at file:line, lies in the
	// product's own module; nil anywhere else.
	Locate(file string, line int, fn string) *model.Source
	// Mails are every mailer's latest mails, at most limit of each.
	Mails(limit int) []model.MailSummary
	// Mail is one mail, whole when its mailer keeps bodies; false when no
	// mailer remembers it.
	Mail(id string) (model.MailMessage, bool)
	// Stores reports whether the app runs on the store subsystem: the
	// Studio's routes on the stores and the databases are mounted only then.
	Stores() bool
	// Databases are the app's databases, each checked and its migrations
	// read again now.
	Databases(ctx context.Context) []model.Database
	// Former are the former values of the record under key in store, as
	// the Studio's data view shows them.
	Former(ctx context.Context, store, key string) (model.RecordHistory, error)
	// Revisions are the versions of the record under key in store, and
	// what changed from version from to version to when both are given.
	Revisions(ctx context.Context, store, key, from, to string) (model.RecordVersions, error)
	// Trash is a page of store's trash, from offset and at most limit
	// records — defaults when they are empty.
	Trash(ctx context.Context, store, offset, limit string) (model.StoreTrash, error)
	// Privacy is what the Studio's Privacy page shows.
	Privacy(ctx context.Context) (model.Privacy, error)
	// Remote reports whether the Studio answers a client that is not on
	// this machine.
	Remote() bool
	// AllowedHost reports whether a request's Host, its port, brackets and
	// case removed, may reach the Studio.
	AllowedHost(host string) bool
	// Reply answers r with body, a JSON document, or with err as the framework
	// answers an error.
	Reply(w http.ResponseWriter, r *http.Request, body json.RawMessage, err error)
	// Forbid answers that the caller may not reach the Studio, saying
	// message.
	Forbid(w http.ResponseWriter, message string)
	// Fail answers an internal error, saying message and nothing of the
	// error.
	Fail(w http.ResponseWriter, message string)
	// NotFound is the framework's answer to a request for what does not exist,
	// saying message.
	NotFound(message string) error
	// Invalid is the framework's answer to a request the caller must change, saying
	// message.
	Invalid(message string) error
	// ProfileUnreadable is the framework's refusal of a profile the process could
	// not read: public says which, cause why, for the logs.
	ProfileUnreadable(public string, cause error) error
	// Debug logs, at the debug level, a failure nobody is told of.
	Debug(ctx context.Context, message string, err error)
}

StudioHost is the running app, as the Studio's routes read it and answer through it.

type StudioStateValue

type StudioStateValue struct {
	// StudioOption and AnalyzeOption are the product's code's choice of the
	// Studio and of the static analysis, which wins over the environment;
	// nil when the code chose nothing.
	StudioOption, AnalyzeOption *bool
	// Studio, Remote and Analyze are the Studio's switches, as resolved and
	// as the settings spell them: on or off.
	Studio, Remote, Analyze string
}

StudioStateValue is what a run resolved of the Studio, and what the product's code chose of it: what the settings show of the tool's variables.

type TableSpec

type TableSpec struct {
	// Name is the table's.
	Name string
	// VersionsOf is, for a store's versions, the store's table, from which
	// the versions' table is named.
	VersionsOf string
}

TableSpec is one of the framework's tables on a database, as the store subsystem's migration makes it: a store's, or a store's versions beside the store's table VersionsOf. A consumer's queue's table is the queue subsystem's (QueueDriverConfig's TableMigration).

type Ticker

type Ticker interface {
	// C receives the clock's instant at each tick.
	C() <-chan time.Time
	// Stop stops the ticker.
	Stop()
	// Reset makes the ticker fire every d.
	Reset(d time.Duration)
}

Ticker is a ticker of a Clock.

type Timer

type Timer interface {
	// C receives the clock's instant when the timer fires.
	C() <-chan time.Time
	// Stop stops the timer, and reports whether it had not fired.
	Stop() bool
	// Reset makes the timer fire once d passed, and reports whether it had
	// not fired.
	Reset(d time.Duration) bool
}

Timer is a timer of a Clock.

type TombstoneValue

type TombstoneValue struct {
	// Key is the trashed record's key.
	Key string
	// At is when the record was trashed, in UTC.
	At time.Time
}

TombstoneValue is one record in a store's trash: its key, and when it was trashed.

type Transaction

type Transaction interface {
	// Local reports whether ctx runs in a transaction that holds the data's
	// writer turn: a write in the data directory or in memory then records
	// what it replaces.
	Local(ctx context.Context) bool
	// Undo keeps restore, which a rollback of the transaction ctx carries
	// runs; nothing outside one. store names the store in a log line.
	Undo(ctx context.Context, store string, restore func(ctx context.Context) error)
	// AtCommit holds fn until the transaction ctx carries commits, and
	// reports whether it did: false outside one, where the caller runs it
	// now.
	AtCommit(ctx context.Context, fn func()) bool
	// Retell keeps fn, which announces a write on a database again when the
	// transaction ctx carries rolls it back.
	Retell(ctx context.Context, fn func())
}

Transaction is the framework's transaction as a store's engine takes part in it (ADR 0139, ADR 0178): the core implements it, an engine calls it with its caller's context.

type TransitionSpec

type TransitionSpec struct {
	// Instant is when a deadline's transition comes due, false for no
	// instant for now; set for WorkflowTriggerDeadline.
	Instant func(e WorkflowEntityValue) (time.Time, bool)
	// Guard is the condition a guard's transition waits for; set for
	// WorkflowTriggerGuard.
	Guard func(e WorkflowEntityValue) bool
	// Event names the transition.
	Event string
	// From is the state it leaves.
	From string
	// To is the state it enters.
	To string
	// Delay is how long a delay's transition waits in From.
	Delay time.Duration
	// Trigger is what fires it: an event, a delay, a deadline or a guard.
	Trigger WorkflowTrigger
}

TransitionSpec declares one transition: an event's, a timer's after a delay or at an instant the entity carries, or a guard's.

type Translator

type Translator interface {
	// Languages are the languages it speaks after English, in order.
	Languages() []string
	// Keys are the keys of lang's catalogue, sorted; nil for a language
	// it does not speak.
	Keys(lang string) []string
	// Render is the sentence of key in lang, its placeholders filled from
	// args by name; a key the catalogue lacks, or a name the sentence
	// takes that args does not give, is an error.
	Render(lang, key string, args map[string]string) (string, error)
}

Translator says the framework's sentences in the languages after English, which only the Studio shows, in its reader's language.

type Trasher

type Trasher interface {
	// Trash moves the record under key to the trash: gone from every read,
	// its index keys freed, its versions kept.
	Trash(ctx context.Context, key string) error
	// Untrash brings the record trashed under key back as it was.
	Untrash(ctx context.Context, key string) error
	// Purge empties the trash of the record trashed under key, its versions
	// with it.
	Purge(ctx context.Context, key string) error
	// Tombstones are every record in the trash, in key order.
	Tombstones(ctx context.Context) ([]TombstoneValue, error)
}

Trasher is an engine that keeps a trash. A sibling of StoreEngine.

type TxOptionsValue added in v0.59.0

type TxOptionsValue struct {
	// Isolation is the transaction's isolation level; zero is the database's default.
	Isolation sql.IsolationLevel
	// ReadOnly tells the database the transaction only reads.
	ReadOnly bool
}

TxOptionsValue is what app.Transact asks of a database transaction: an isolation level — the zero value the database's default — and whether it only reads. A savepoint is given the zero value.

type VersionKeeper

type VersionKeeper interface {
	// StoredVersions are the versions of the record under key, newest
	// first, the current one first.
	StoredVersions(ctx context.Context, key string) ([]VersionValue, error)
	// RewriteVersions rewrites the former versions of the record under key
	// as fn returns them: fn may drop a version or change what one holds,
	// never add or renumber one.
	RewriteVersions(ctx context.Context, key string, fn func(vs []VersionValue) ([]VersionValue, error)) error
}

VersionKeeper is an engine that keeps its records' versions. A sibling of StoreEngine.

type VersionValue

type VersionValue struct {
	// Number counts a record's versions from 1.
	Number uint64
	// At is when the write that made the version ran, in UTC.
	At time.Time
	// Meta is what the write said about it: who made it, which command.
	Meta map[string]string
	// JSON is the record as the version holds it.
	JSON json.RawMessage
}

VersionValue is one version of a record: its number, when the write that made it ran, what that write said about it, and the record as it held it.

type VersionWeightValue

type VersionWeightValue struct {
	// Former is how many former versions the store keeps.
	Former int
	// Trashed is how many records are in the trash.
	Trashed int
	// Bytes is what the former versions and the trashed records weigh.
	Bytes int64
}

VersionWeightValue is what a store keeps beyond the records it holds: its former versions and its trash, counted and weighed.

type VersionWeighter

type VersionWeighter interface {
	// VersionWeight is what the store's versions and trash weigh.
	VersionWeight(ctx context.Context) (VersionWeightValue, error)
}

VersionWeighter is an engine that says what its records' versions weigh. A sibling of StoreEngine.

type WordsConfig

type WordsConfig struct {
	// Open reads and compiles the catalogue of every language after
	// English, each falling back to english — the framework's own sentences, by
	// key, as its core holds them; a catalogue that does not decode or
	// does not compile is refused.
	Open func(english map[string]string) (Translator, error)
}

WordsConfig is what framework/app/studio plugs into kit: how the framework's catalogues in the languages after English open.

type WorkflowChangeValue

type WorkflowChangeValue struct {
	// At is when it happened.
	At time.Time
	// Entity is the entity, as stored after the transition.
	Entity WorkflowEntityValue
	// Key is the entity's key.
	Key string
	// Event is the transition's name; WorkflowCreateEvent for Start.
	Event string
	// From is the state left, "" on creation.
	From string
	// To is the state entered.
	To string
	// Actor is who fired it, "" for the loop.
	Actor string
	// Trigger is what fired it.
	Trigger WorkflowTrigger
}

WorkflowChangeValue is one stored transition: the entity as stored after it, the states it left and entered, what fired it, who and when.

type WorkflowConfig

type WorkflowConfig struct {
	// Store is the workflow's entities, as the engine reads and writes them.
	Store WorkflowStore
	// Journal keeps what the engine knows of each entity — its state, since
	// when, its latest transitions —; nil keeps it in memory alone.
	Journal WorkflowJournal
	// Clock is the app's clock, which the engine stamps and waits on.
	Clock Clock
	// Actor names, from the context of a transition someone fired, who
	// fired it.
	Actor func(ctx context.Context) string
	// Observe brackets each transition the loop fires: the context it runs
	// with, and the function told how it ended.
	Observe func(ctx context.Context, f WorkflowFiringValue) (context.Context, func(err error))
	// Report receives what the engine reports and no caller's return value
	// carries: an OnTransition hook that failed, a panic, a journal's write
	// that failed.
	Report func(ctx context.Context, err error)
	// OnLoop is told each run of the loop, and each wait.
	OnLoop func(e WorkflowLoopEventValue)
	// Initial is the state Start enters an entity in.
	Initial string
	// Transitions are the declared transitions, in declaration order.
	Transitions []TransitionSpec
	// OnEnter are the hooks run as an entity enters a state, in
	// declaration order.
	OnEnter []EnterHookSpec
	// OnTransition are the hooks run after every stored transition, in
	// declaration order.
	OnTransition []func(ctx context.Context, c WorkflowChangeValue) error
	// MinGap is the least a wake for a due transition waits after a run.
	MinGap time.Duration
	// BackoffBase is the wait after a run that failed, doubled after each,
	// up to BackoffMax.
	BackoffBase time.Duration
	// BackoffMax bounds the wait after a run that failed.
	BackoffMax time.Duration
	// MaxHistory caps the transitions remembered per entity.
	MaxHistory int
}

WorkflowConfig is one workflow as its engine runs it: its states and transitions, its hooks, the store and the journal it runs over, and how the app's loop, clock and spans see it.

type WorkflowDriverConfig

type WorkflowDriverConfig struct {
	// Open opens the engine of one workflow, as cfg declares it: it reads
	// the journal and every entity of the store once.
	Open func(ctx context.Context, cfg *WorkflowConfig) (WorkflowEngine, error)
	// Failed reports whether err, or an error it wraps, is the engine's
	// failure of kind: the SDK's sentinels stay in the subsystem, and the
	// error keeps the fields the engine gave it.
	Failed func(err error, kind WorkflowFailure) bool
}

WorkflowDriverConfig is what framework/app/workflow plugs into kit: how a workflow's engine opens, and how the framework tells the engine's failures apart.

type WorkflowEngine

type WorkflowEngine interface {
	// Start enters e in the workflow, in the initial state: its OnEnter
	// hooks run, then it is inserted in the store.
	Start(ctx context.Context, e WorkflowEntityValue) (WorkflowEntityValue, error)
	// Fire moves the entity under key along the event's transition leaving
	// its state.
	Fire(ctx context.Context, key, event string) (WorkflowEntityValue, error)
	// Changed tells the engine the entity under key was written.
	Changed(ctx context.Context, key string) error
	// Deleted tells the engine the entity under key was deleted.
	Deleted(ctx context.Context, key string) error
	// Census counts the entities per state.
	Census() map[string]int
	// Records are what the engine knows of each entity.
	Records() []WorkflowRecordValue
	// Run runs the loop that fires the timers and the guards, until ctx
	// ends.
	Run(ctx context.Context) error
}

WorkflowEngine is one workflow's engine as the framework's core uses it: the transitions code fires, what a write of the store tells it, what it counts and records, and its loop.

type WorkflowEntityValue

type WorkflowEntityValue struct {
	// Value is the product's entity.
	Value any
	// State is the entity's state, spelled.
	State string
}

WorkflowEntityValue is one entity as a workflow's engine holds it: the product's, kept as any — the workflow's typed facade asserts it to its type —, and its state as the facade spells it, which the engine reads and sets.

type WorkflowFailure

type WorkflowFailure uint8

WorkflowFailure is a failure of a workflow's engine, as the framework words it.

const (
	// WorkflowFailureNone is no failure the framework words.
	WorkflowFailureNone WorkflowFailure = iota
	// WorkflowTransitionRefused is an event that leaves no transition from
	// the entity's state.
	WorkflowTransitionRefused
	// WorkflowEntityMissing is no entity under the key.
	WorkflowEntityMissing
	// WorkflowEntityExists is an entity already under the key Start names.
	WorkflowEntityExists
	// WorkflowKeyEmpty is an entity whose key is empty.
	WorkflowKeyEmpty
	// WorkflowHookFailed is a hook that returned an error, joined to it;
	// its "hook" and "event" fields name the hook's kind and the event.
	WorkflowHookFailed
	// WorkflowHookPanicked is a hook that panicked; its "hook", "panic" and
	// "stack" fields say which and how.
	WorkflowHookPanicked
	// WorkflowHookChangedState is an OnEnter hook that changed the state
	// it entered.
	WorkflowHookChangedState
	// WorkflowHookChangedKey is an OnEnter hook that changed its entity's
	// key.
	WorkflowHookChangedKey
	// WorkflowReentrant is an OnEnter hook that fired its own workflow.
	WorkflowReentrant
	// WorkflowStoreFailed is the workflow's store that failed.
	WorkflowStoreFailed
	// WorkflowJournalFailed is the workflow's journal that failed.
	WorkflowJournalFailed
	// WorkflowFunctionPanicked is a guard or an instant function that
	// panicked.
	WorkflowFunctionPanicked
	// WorkflowLoopPanicked is the loop that panicked.
	WorkflowLoopPanicked
	// WorkflowWaitAbandoned is a caller that stopped waiting for its
	// entity: its context ended.
	WorkflowWaitAbandoned
)

The engine's failures the framework tells apart, which it words for the product.

type WorkflowFiringValue

type WorkflowFiringValue struct {
	// Key is the entity's key.
	Key string
	// Event is the transition's name.
	Event string
	// From is the state it leaves.
	From string
	// To is the state it enters.
	To string
	// Trigger is what fires it.
	Trigger WorkflowTrigger
}

WorkflowFiringValue is one transition the loop is about to fire: the entity's key, the event, the states it leaves and enters, and its trigger.

type WorkflowJournal

type WorkflowJournal interface {
	// Load reads every record the journal kept.
	Load(ctx context.Context) ([]WorkflowRecordValue, error)
	// Save keeps records, in the transaction ctx carries for a database.
	Save(ctx context.Context, records ...WorkflowRecordValue) error
	// Delete forgets the records of keys; one already gone is no error.
	Delete(ctx context.Context, keys ...string) error
}

WorkflowJournal is the port a workflow's engine keeps what it knows of each entity in: the workflow's file under the data directory, or its table on the database that keeps its store.

type WorkflowLoopEvent

type WorkflowLoopEvent uint8

WorkflowLoopEvent is what a workflow's loop reports.

const (
	// WorkflowLoopOther is an event of the loop the framework shows nothing of.
	WorkflowLoopOther WorkflowLoopEvent = iota
	// WorkflowLoopRunStarted is a run starting: Wake and Started are set.
	WorkflowLoopRunStarted
	// WorkflowLoopRunEnded is a run ending: Started, Ended, Next and what
	// it could not fire, Err, are set.
	WorkflowLoopRunEnded
	// WorkflowLoopWaiting is the loop asleep until Next, zero for no
	// transition due.
	WorkflowLoopWaiting
)

What a workflow's loop reports.

type WorkflowLoopEventValue

type WorkflowLoopEventValue struct {
	// Err is what a run could not fire, nil for nothing.
	Err error
	// Started is when the run started.
	Started time.Time
	// Ended is when the run ended.
	Ended time.Time
	// Next is when the loop wakes next, zero for no transition due.
	Next time.Time
	// Kind is what the event reports.
	Kind WorkflowLoopEvent
	// Wake is why the run started.
	Wake WorkflowWake
}

WorkflowLoopEventValue is what a workflow's loop reports: a run started, a run ended, a wait.

type WorkflowRecordValue

type WorkflowRecordValue struct {
	// Entered is when the entity entered its state.
	Entered time.Time
	// Key is the entity's key.
	Key string
	// State is the entity's state.
	State string
	// History are its latest transitions, oldest first.
	History []WorkflowStepValue
}

WorkflowRecordValue is what a workflow's engine knows of one entity: its state, since when, and its latest transitions, oldest first.

type WorkflowStepValue

type WorkflowStepValue struct {
	// At is when it happened.
	At time.Time
	// Event is the transition's name.
	Event string
	// From is the state left, "" on creation.
	From string
	// To is the state entered.
	To string
	// Actor is who fired it, "" for the loop.
	Actor string
	// Trigger is what fired it.
	Trigger WorkflowTrigger
}

WorkflowStepValue is one transition of an entity's history: the event, the states it left and entered, what fired it, who and when.

type WorkflowStore

type WorkflowStore interface {
	// Key is e's key.
	Key(e WorkflowEntityValue) string
	// Get reads the entity under key; false when there is none.
	Get(ctx context.Context, key string) (WorkflowEntityValue, bool, error)
	// Insert writes e unless its key is taken; false when it was.
	Insert(ctx context.Context, e WorkflowEntityValue) (bool, error)
	// Replace writes e over the entity of its key; false when there was
	// none.
	Replace(ctx context.Context, e WorkflowEntityValue) (bool, error)
	// All yields every entity of the store.
	All(ctx context.Context) iter.Seq2[WorkflowEntityValue, error]
}

WorkflowStore is the port a workflow's engine reads and writes its entities through: the workflow's store.

type WorkflowTrigger

type WorkflowTrigger uint8

WorkflowTrigger is what fires a transition.

const (
	// WorkflowTriggerStart is a creation, which Start fires.
	WorkflowTriggerStart WorkflowTrigger = iota
	// WorkflowTriggerEvent is an event code fires.
	WorkflowTriggerEvent
	// WorkflowTriggerDelay is a timer: a duration spent in a state.
	WorkflowTriggerDelay
	// WorkflowTriggerDeadline is a timer at an instant the entity carries.
	WorkflowTriggerDeadline
	// WorkflowTriggerGuard is a condition on the entity that holds.
	WorkflowTriggerGuard
)

The triggers of a transition.

type WorkflowWake

type WorkflowWake uint8

WorkflowWake is why a run of a workflow's loop started.

const (
	// WorkflowWakeStart is the loop's first run.
	WorkflowWakeStart WorkflowWake = iota
	// WorkflowWakeDue is a transition coming due.
	WorkflowWakeDue
	// WorkflowWakeChange is a write that may have brought one forward.
	WorkflowWakeChange
)

Why a run of a workflow's loop started.

type WriteMode

type WriteMode int

WriteMode says what a write expects to find under the document's key.

const (
	// WriteUpsert writes whatever the key holds: a creation or a
	// replacement.
	WriteUpsert WriteMode = iota
	// WriteInsert expects nothing under the key, and is refused otherwise.
	WriteInsert
	// WriteReplace expects a document under the key, and is refused
	// otherwise: never a resurrection.
	WriteReplace
)

The write modes.

Jump to

Keyboard shortcuts

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