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

engine

package
v0.21.0 Latest Latest
Warning

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

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

Documentation

Overview

Package engine is the heart of Atlas: a single-writer processor that folds commands into durable events and applies them to state.

One partition is driven by one goroutine (invariant I3), so there are no locks on process state. Each batch follows the fixed order append → one fsync → commit state → side effects (invariants I2, ADR-0005). State changes from a record happen in exactly one place, applyToState, used identically live and on recovery (invariant I4), which is what makes crash recovery a simple replay.

The processor path is allocation-free per command and per event (invariant I1): payloads flow by value (see inflightValue), and the batch buffers, queue, side-effect list, and encode buffer are reused across batches. State reads (which decode from the store) and the per-batch state transaction are the remaining allocation sources, tracked separately.

Index

Constants

View Source
const AgentCallIdVariable = "toolCallId"

AgentCallIdVariable is the variable an activated tool carries in its own scope naming the call it answers, so a result can be paired back to the call that asked for it.

View Source
const ApprovalRequiredErrorCode = "ATLAS_APPROVAL_REQUIRED"

ApprovalRequiredErrorCode is the BPMN error an enforced refusal throws when what is missing is an approval. A model that plans for approval catches it and routes to a user task; one that does not parks on an incident, which is the right answer for a process that never said what should happen.

View Source
const DefaultExecutionBudget int32 = 10_000

DefaultExecutionBudget is how many element activations one token may drive in a single run before the engine parks it with an incident. Ten thousand is far above any plausible stretch of automatic work for one token — a token that has taken ten thousand sequence flows without once waiting for a job, a timer or a message is not making progress a person modelled — and low enough that the writer comes back in well under a second.

View Source
const DefaultMaxCollection int64 = 16 << 20

DefaultMaxCollection is how large a multi-instance activity's output collection may be. It has to clear a legitimate loop at the iteration ceiling — a hundred thousand modest results — while staying far below what costs the host its memory.

View Source
const DefaultMaxIterations = 100_000

DefaultMaxIterations is how many iterations one multi-instance activity may ask for before the engine refuses it with an incident.

It is a *size* budget where DefaultExecutionBudget is a *rate* one, and neither substitutes for the other: a hundred thousand iterations are a hundred thousand tokens taking one step each, which the execution budget is deliberately built not to stop. What makes them dangerous is that the count comes from the model or from an instance variable, and the engine allocated from it before looking — a variable holding a billion is a billion FEEL nulls, asked for in one call (ADR-0276).

A hundred thousand is far above what a modelled loop plausibly wants and far below the point where the allocation is the problem.

View Source
const DefaultMaxVariable int64 = 1 << 20

DefaultMaxVariable is how large one variable's value may be. A megabyte holds a business record with room to spare; past that it is a document, and a document in a token's scope is rewritten into the log on every touch.

View Source
const LoopCounterVariable = compiler.LoopCounterVariable

LoopCounterVariable is the standard multi-instance per-iteration counter variable (1-based), bound into each inner iteration's scope (ADR-0077, matching Zeebe). Exported so read-side surfaces can name the variable they are looking for without re-inventing the string and drifting from what the engine actually writes. It is the compiler's constant, so the deploy check that keeps a model from mapping onto it (loop.counter-mapping) and the runtime that writes it can never disagree.

Variables

View Source
var BuildVersion string

BuildVersion is the Atlas build recorded in checkpoint manifests for diagnostics (ADR-0131). It is metadata only — nothing branches on it — and the server may stamp it at startup; an unset value simply records no version.

View Source
var ErrHalted = errors.New("engine halted: a batch could not be made durable, so nothing more is processed until the server is restarted")

ErrHalted is what every run reports once a batch could not be made durable: the engine processes nothing more until the process is restarted (ADR-0481).

The reason is the queue, not the disk. A failed batch leaves its commands queued in memory, and their callers have already been told they failed. Running them later — once space is back — would contradict that answer: an instance whose creation was refused would be created anyway, and a client that retried would have it twice. After a failure only a restart knows exactly what is durable, because recovery reads it from the log, so a restart is where the engine resumes. Reads go on meanwhile: the state store holds every batch that committed, and nothing past it.

Functions

This section is empty.

Types

type ApplicationInfo added in v0.13.0

type ApplicationInfo struct {
	Key  string // the portable application key (ADR-0134), the same on every installation
	Name string
}

ApplicationInfo is what the application namespace says about the application a definition is filed under, besides its constants.

type ApprovalAnswer added in v0.20.0

type ApprovalAnswer uint8

ApprovalAnswer is what an approver's answer, or a withdrawal, did.

const (
	ApprovalNotProcessed ApprovalAnswer = iota
	// ApprovalRecordedAnswer: the answer or withdrawal is a fact.
	ApprovalRecordedAnswer
	// ApprovalUnknown: the instance holds no request of that key.
	ApprovalUnknown
	// ApprovalClosed: the request expired before the answer arrived.
	ApprovalClosed
	// ApprovalAlreadyAnswered: this principal has an answer standing; withdraw it first.
	ApprovalAlreadyAnswered
	// ApprovalNothingToWithdraw: this principal has no standing answer.
	ApprovalNothingToWithdraw
	// ApprovalInvalid: the fact is neither an answer nor a withdrawal, or names nobody.
	ApprovalInvalid
)

type ApprovalResult added in v0.20.0

type ApprovalResult struct {
	Answer  ApprovalAnswer
	Request model.ActionApprovalValue
}

ApprovalResult is written through Command.Approved. Request is the request the fact was checked against, when there was one.

type Arrival added in v0.6.0

type Arrival struct {
	Key  uint64
	Flow int32
}

Arrival is one token waiting on a join: the element instance holding it and the incoming sequence flow it came in on.

The flow is what a join has to count by. BPMN 2.0.2 §13.4 activates a parallel gateway when there is at least one token on *each* incoming sequence flow, and consumes exactly one from each — which is a different question from how many tokens are on the node, and gives a different answer whenever a flow carries two (ADR-0290).

type AuthorizationAnswer added in v0.20.0

type AuthorizationAnswer uint8

AuthorizationAnswer is what recording a decision did.

const (
	// AuthorizationNotProcessed is the zero value: the command never ran.
	AuthorizationNotProcessed AuthorizationAnswer = iota
	// AuthorizationRecorded: the decision is a fact, and its consequence with it.
	AuthorizationRecorded
	// AuthorizationStale: the job is no longer held under the lease the decision was
	// made for — completed, re-leased, failed. Nothing was written, and nothing may be
	// released on the strength of it.
	AuthorizationStale
)

type AuthorizationResult added in v0.20.0

type AuthorizationResult struct {
	Answer      AuthorizationAnswer
	DecisionKey uint64
	// ApprovalKey is the approval the refusal asked for: a new request, or the open
	// one for the same action that it joined.
	ApprovalKey uint64
}

AuthorizationResult is written through Command.Authorized.

type BatchStats added in v0.2.0

type BatchStats struct {
	// Commands is how many queued commands the batch consumed.
	Commands int
	// Events is how many events it made durable — zero for a batch whose commands
	// produced nothing to write.
	Events int
	// QueueDepth is how many commands remain queued after the batch, including the
	// follow-ups it scheduled. It is the backpressure signal: a depth that climbs
	// batch over batch means the writer is not keeping up with what is arriving.
	QueueDepth int
	// SyncSeconds is how long the batch's single group-commit fsync took.
	SyncSeconds float64
	// CommitSeconds is how long making the batch's state visible took.
	CommitSeconds float64
	// Jobs is what the batch did to the job lifecycle (ADR-0142 slice 5).
	Jobs JobStats
}

BatchStats is what one durably committed batch did. It is passed by value and never retained by the engine.

SyncSeconds and CommitSeconds are zero for a batch that produced no events: there was nothing to fsync and nothing to commit, so an implementation should record no observation rather than a zero one, which would drag a latency histogram down.

type CallTargetOverride

type CallTargetOverride struct {
	// Disabled parks the call (as an undeployed callee does) instead of resolving.
	Disabled bool
	// PinnedDefKey resolves to exactly this definition key (0 = not pinned). The
	// server layer picks the key from an operator-named version; the engine is
	// version-agnostic and simply uses it, parking if it is no longer deployed.
	PinnedDefKey uint64
	// RedirectProcessId resolves the newest deployment of this process id instead of
	// the called one ("" = no redirect). A redirect uses the default `latest`
	// resolution for its target (no chaining), so overrides cannot form a cycle.
	RedirectProcessId string
}

CallTargetOverride redirects, pins, or disables a call activity's target on this server (ADR-0105). Exactly one shape is meaningful per record; the resolution precedence (see ProcessingContext.resolveCallTarget) is Disabled, then PinnedDefKey, then RedirectProcessId, else the default `latest` resolution. It is operator config, not derived from deployments and not event-sourced — it changes only future resolutions; a child already created carries its frozen def key, so replay is unaffected (I6).

type Clock

type Clock interface {
	Now() int64 // unix nanoseconds
}

Clock supplies wall-clock time. It is injected so tests can drive time deterministically (invariant I4: time is read into events, never inside applyToState).

type Command

type Command struct {
	Key       uint64
	ValueType model.ValueType
	Intent    model.Intent
	Value     inflightValue
	// SourcePos is the log position of the event that scheduled this command
	// (0 for externally submitted commands), used to thread causality into the
	// events the command produces.
	SourcePos uint64
	// StartVars carries variables attached to a command: the initial variables for
	// a process-instance creation command, or the output variables a worker
	// produced for a job-completion command. Both are external, non-hot-path
	// intents, so a slice here does not affect the token-movement fast path.
	StartVars []model.VariableValue
	// StartElements names the root start events an instance-creation command seeds a
	// token at. A *triggered* start — a correlating message, a broadcast signal, a
	// fired start timer — carries exactly the one that fired, because a start event is
	// a trigger and the one that happened is the one that instantiates.
	//
	// nil is the untriggered create (the API, a call activity), which seeds the
	// process's own entry points instead; see startElementsFor. The zero value is
	// therefore the safe one: a command that forgets to say what triggered it starts
	// the process the way pressing Start does, never at somebody else's trigger.
	//
	// It rides only on the non-hot-path creation intent, alongside StartVars, so it
	// never touches token movement (invariant I1).
	StartElements []int32
	// Decision carries a DMN decision evaluation a worker produced for a
	// job-completion command (ADR-0066): the inputs, outputs, and trace it froze off
	// the processor goroutine, recorded as history when the completion is folded. It
	// is nil for every other command and for job completions that are not decisions,
	// so — like StartVars, on the same non-hot-path completion intent — it never
	// touches the token-movement fast path.
	Decision *model.DecisionEvaluationValue
	// ToolCalls carries the tools an agent chose for the next round of an agent-driven
	// ad-hoc subprocess (ADR-0253), riding on that container's job-completion command the
	// way Decision rides on a business rule task's. It is engine control data, not process
	// data: putting it in StartVars would leak it into FEEL, the variable timeline and
	// every downstream expression. Empty for every other command — and an empty list on
	// an agent container's completion is the agent saying it is done, which is why the
	// zero value is the ending, not an error.
	ToolCalls []model.ToolCall
	// Actor identifies who submitted an external variable-modify command (ADR-0098):
	// the acting principal's username, frozen into the audit event the modify emits so
	// the "who changed it" trail is durable and replayable. Empty for every other
	// command (and for a modify made with auth off / by an unidentified caller). It
	// rides only on the non-hot-path IntentVariableModify command, so it never touches
	// the token-movement fast path.
	Actor string
	// Reason is the operator's justification for an intervention that forces a step the
	// engine would not have taken on its own — completing a parked job by hand (ADR-0159).
	// It rides only on such a command, alongside Manual, and is frozen into the audit event
	// the handler emits, so "why" is as durable and replayable as "who". Empty for every
	// other command, so it never touches the token-movement fast path.
	Reason string
	// Manual marks a completion an operator forced rather than a worker reporting real
	// work (ADR-0159). It is the explicit gate for the audit record — never inferred from
	// Reason being set — so a manual completion is always attributable even if the reason
	// is somehow empty, and a worker's completion never mints an operator-action record.
	// A BPMN error thrown by hand carries it for the same reason (ADR-0089).
	Manual bool
	// ErrorMessage is what a worker said about the BPMN error it threw (ADR-0089), the
	// text an operator reads on the incident when nothing catches the error. It rides
	// only on the non-hot-path IntentJobErrorThrown command, beside the code in
	// Value.incident.Message, so it never touches the token-movement fast path.
	ErrorMessage string
	// RetryBackoff is the delay (unix-nanoseconds) a worker asked to wait before its failed
	// job may be retried (ADR-0111). It rides only on the non-hot-path IntentJobFailed command;
	// the handler reads the clock at command time and freezes now+RetryBackoff into the job's
	// RetryDueDate (invariant I6). 0 means retry immediately (the pre-0111 behavior).
	RetryBackoff int64
	// LeaseFor is how long (in nanoseconds) a worker asked to hold a job it is activating
	// (ADR-0007). It rides only on the non-hot-path IntentJobActivated command; like
	// RetryBackoff, the handler reads the clock at command time and freezes
	// now+LeaseFor into the job's LeaseExpiresAt, so a replay lands on the same instant
	// (invariant I6).
	LeaseFor int64
	// Created, when set, is where an instance-creation command reports the key the
	// new instance was given. The key is minted while the command is processed, so a
	// caller that needs it — the API start, which records which instance works an
	// order's position — cannot know it before, and nothing afterwards could tell its
	// instance from one another caller started in the same batch.
	//
	// Written on the processor goroutine during RunUntilIdle and read by the caller
	// only after that returned without error, so it is read once the instance is
	// durable (invariant I2) and the loop's rendezvous orders the two. nil on every
	// other command; it rides only on the non-hot-path creation intent, and a
	// pointer the caller owns allocates nothing here (invariant I1). Commands are
	// never replayed (I6), so recovery never writes through it.
	Created *uint64
	// Triggered is where a directed trigger's answer is written (ADR-0425): whether
	// it created an instance, answered from a receipt, or was refused and why. The
	// same contract as Created — written on the processor goroutine, read after
	// RunUntilIdle returned, never on a replayed command.
	Triggered *TriggerResult
	// Delivered is where a directed delivery's answer is written
	// (ADR-0428), under the
	// same contract as Triggered.
	Delivered *DeliveryResult
	// Reported is where an action outcome report's answer is written (ADR-0429 §3):
	// recorded now, answered from the record, or refused as a second ending of the
	// same command. Same contract as Triggered.
	Reported *OutcomeResult
	// Authorized is where a decision's recording is answered
	// (ADR-0475): recorded, or refused because the
	// lease it was made for is gone. Same contract as Triggered.
	Authorized *AuthorizationResult
	// Approved is where an approver's answer is answered. Same contract as Triggered.
	Approved *ApprovalResult
	// MessageTTL is how long a published message stays useful when nothing waits for
	// it yet (ADR-0370): zero, the default, keeps ADR-0020's no-op for an unmatched
	// publish, and a positive value buffers it for a subscription that opens later.
	// It rides only on a client's publish command, never on token movement.
	MessageTTL time.Duration
	// MessageID is the sender's id for a published message, "" for none. With a
	// MessageTTL it makes a repeat of the same message a no-op while the first lives.
	MessageID string
}

Command is an intention handed to the processor. Commands are processed but never persisted (only the events they produce are); on recovery they are not replayed (invariant I6). The payload is held by value (see inflightValue) so queuing a command does not allocate.

type ConstantValue added in v0.13.0

type ConstantValue struct {
	Kind model.VarKind
	Bool bool
	Text string
}

ConstantValue is the value of one constant the installation holds — for an application or for every application — in the canonical form a variable is stored in (ADR-0453, ADR-0456). The server layer parses it when it is saved, so the engine seeds it without parsing (I5).

type DeliveryOutcome added in v0.8.0

type DeliveryOutcome uint8

DeliveryOutcome is what a directed delivery did.

const (
	// DeliveryNotProcessed is the zero value: the command never ran.
	DeliveryNotProcessed DeliveryOutcome = iota
	// DeliveryDelivered: the instance was waiting for this message and took it.
	DeliveryDelivered
	// DeliveryReplayed: this sender delivered this trigger id before; nothing was
	// delivered now, and the answer names the instance that took it then.
	DeliveryReplayed
	// DeliveryNotWaiting: the instance is running but holds no open subscription for
	// this message under this correlation key — it is still being provisioned, or busy
	// in a step that does not listen for it. Nothing was delivered or buffered.
	DeliveryNotWaiting
	// DeliveryGone: no running instance has this key — it finished, was cancelled, or
	// never existed.
	DeliveryGone
)

type DeliveryResult added in v0.8.0

type DeliveryResult struct {
	Outcome     DeliveryOutcome
	InstanceKey uint64
	// Elements are the BPMN element indexes of the subscriptions that took the
	// message; empty unless Outcome is DeliveryDelivered.
	Elements []int32
}

DeliveryResult is written through Command.Delivered.

type JobStats added in v0.2.0

type JobStats struct {
	// Created counts jobs that became available to a worker.
	Created int
	// Activated counts leases taken — a worker pulled a job and now holds it
	// (ADR-0007). Without it, a queue nobody is pulling from and a queue being worked
	// through are the same picture: jobs created, none finished yet.
	Activated int
	// Completed counts jobs a worker finished successfully.
	Completed int
	// Failed counts worker-reported failures. A failure with retries left leaves the
	// job open for another attempt; one without parks it with an incident (ADR-0061).
	Failed int
	// TimedOut counts leases that elapsed with no report, returning the job to the
	// index. This is the only durable trace of a worker that took work and vanished:
	// Failed never sees it, because a worker that dies reports nothing. A rate above
	// roughly zero means workers are crashing, or the lease is shorter than the work.
	TimedOut int
	// Canceled counts jobs removed without being worked — their element was
	// interrupted, terminated, or its instance cancelled.
	Canceled int
}

JobStats counts the job-lifecycle transitions one batch made durable. It rides on BatchStats rather than a separate call so it inherits the same durability ordering: a job is counted as created only once the event that created it is on disk.

The six counts are the job's whole durable lifecycle. Created and Completed alone would answer "is the queue growing", and no more: the two lease transitions carry the facts a create/complete/fail triple structurally cannot.

type Metrics added in v0.2.0

type Metrics interface {
	// BatchCommitted reports a batch whose events are durable and whose state is
	// committed. It is never called for a batch that failed.
	BatchCommitted(BatchStats)
	// SyncFailed reports a batch whose group-commit fsync failed. Nothing it wrote is
	// durable.
	SyncFailed()
	// CommitFailed reports a batch whose events are durable but whose state commit
	// failed. Recovery will re-apply them from the log.
	CommitFailed()
}

Metrics observes the batch loop. Every method is called from the single-writer goroutine (invariant I3), so an implementation must not block, must not call back into the processor, and must not allocate (invariant I1).

A nil Metrics — the default — means the engine reports nothing and does not even read the clock, so an uninstrumented processor pays literally nothing.

type MigrationElement added in v0.3.0

type MigrationElement struct {
	Key             uint64
	ElementId       int32
	FlowScopeKey    uint64
	BpmnElementType uint8
	MultiInstance   uint8
	EventGatewayKey uint64
	AttachedToKey   uint64
}

MigrationElement is one live element instance, as the migration validator needs to see it. It is a plain struct rather than model.ElementInstanceValue so the validator can be called from the API — which reads the store — and from the processor — which reads the in-flight transaction — over the same rules (ADR-0162).

func MigrationElementOf added in v0.3.0

func MigrationElementOf(key uint64, ei *model.ElementInstanceValue) MigrationElement

MigrationElementOf projects a stored element instance onto what the validator reads.

type MigrationProblem added in v0.3.0

type MigrationProblem struct {
	ElementInstanceKey uint64 `json:"elementInstanceKey"`
	ElementID          string `json:"elementId"`
	Reason             string `json:"reason"`
}

MigrationProblem is one reason a migration is refused, named so an operator can act on it: which element instance, which element the modeler would recognise, and what is wrong with moving it.

func ValidateFork added in v0.7.0

func ValidateFork(from, to *compiler.CompiledProcess, parent uint64, resume []int32) []MigrationProblem

ValidateFork reports every reason an instance cannot be forked onto the target version at the given resume points: ended where it is, and continued as a new instance of `to` starting at those elements (ADR-0389).

A fork is what an operator reaches for when ValidateMigration has refused — the token sits on an element the target version no longer has, or has as something else, so there is no honest way to rebind it. What crosses instead is the instance's data and a human's decision about where the work picks up again. That decision is the one thing this cannot check, so everything around it is checked strictly: a resume point that cannot seed an execution is refused before anything is written, because the alternative is a terminated predecessor and a successor that can never run.

It is a pure function of its arguments, called by the API to refuse before submitting a command and again by the processor on the run loop, where the instance may have moved since. `parent` is the instance's ParentElementInstanceKey. It never runs inside applyToState (invariant I4).

func ValidateMigration added in v0.3.0

func ValidateMigration(from, to *compiler.CompiledProcess, live []MigrationElement, mapping map[int32]int32) []MigrationProblem

ValidateMigration reports every reason the given mapping cannot rebind these live element instances from the `from` definition to the `to` one. An empty result means the migration is safe to submit; anything else refuses it (ADR-0162).

It refuses rather than guesses, and that is the whole point of it. A token left on an index that means something else in the target graph, or landed on an element of another type, corrupts an instance in a way no later fix repairs — while a refused migration costs an operator one message. So every rule here answers "could this rebinding produce an instance the engine can still run correctly?", and anything it cannot answer yes to is a problem.

It is a pure function of its arguments: the API calls it to refuse before submitting a command, and the processor calls it again on the run loop, where the state may have moved since. It never runs inside applyToState — the fold reads the mapping the event froze and computes nothing (invariant I4).

type OutcomeAnswer added in v0.9.0

type OutcomeAnswer uint8

OutcomeAnswer is what an outcome report did.

const (
	// OutcomeNotProcessed is the zero value: the command never ran.
	OutcomeNotProcessed OutcomeAnswer = iota
	// OutcomeRecorded: the outcome is now a fact.
	OutcomeRecorded
	// OutcomeReplayed: the same outcome was reported before; nothing was written.
	OutcomeReplayed
	// OutcomeConflict: the command already ended differently; nothing was written.
	OutcomeConflict
	// OutcomeInvalid: the report names no command or no ending.
	OutcomeInvalid
)

type OutcomeResult added in v0.9.0

type OutcomeResult struct {
	Answer   OutcomeAnswer
	Recorded model.ActionOutcomeValue
}

OutcomeResult is written through Command.Reported. Recorded is the outcome as it stands after the command: the one written now, or the one already there.

type ProcessingContext

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

ProcessingContext is the surface every behavior works through while a command is processed. A behavior may do three things: read state, write events (a fact that also mutates state), and schedule what comes next. It never touches the log or fsync directly — it only accumulates into the batch (invariant I2: nothing becomes visible before the batch is durable).

func (*ProcessingContext) ActiveChildren

func (c *ProcessingContext) ActiveChildren(scope uint64) int32

ActiveChildren returns the active-child count of a scope (e.g. to detect that a process instance has finished).

func (*ProcessingContext) AppendCompensableEvent

func (c *ProcessingContext) AppendCompensableEvent(intent model.Intent, v model.CompensableValue)

AppendCompensableEvent records a compensation-index change: IntentCompensableRecorded retains a completed compensable activity (keyed under its scope in completion order), and IntentCompensableConsumed drops one once it has been compensated (ADR-0103). Both ride only on the command path (a completion or a compensation throw), never token movement; applyToState folds them into the compensable index so recovery rebuilds it (invariant I6). Keyed by the owning process instance, like the other history events.

func (*ProcessingContext) AppendCreateChildInstanceCommand

func (c *ProcessingContext) AppendCreateChildInstanceCommand(defKey uint64, vars []model.VariableValue, parentElementKey uint64)

AppendCreateChildInstanceCommand is AppendCreateInstanceCommand for a call activity: the created instance records the caller's call-activity element instance as its parent, so on completion it resumes that element (ADR-0076).

func (*ProcessingContext) AppendCreateInstanceCommand

func (c *ProcessingContext) AppendCreateInstanceCommand(defKey uint64, vars []model.VariableValue, correlationKey string, startElement int32)

AppendCreateInstanceCommand schedules creation of a new instance of defKey for a later batch, seeded with vars (each re-scoped to the new instance when it is created) and the correlationKey the created instance records (empty for a timer or signal start). A correlating message uses it to instantiate a message-start process (ADR-0035). Deferring to a followup keeps instance creation on the same command path as an API-submitted create, so its events — and thus recovery — are identical however the create was triggered.

startElement is the root start event that fired, and every caller here has one: a trigger instantiates at itself, not at every entry the process happens to have (ADR-0226). It is a required argument rather than an optional one so that adding a fourth kind of trigger cannot quietly inherit the old seed-everything behaviour.

func (*ProcessingContext) AppendDataObjectEvent

func (c *ProcessingContext) AppendDataObjectEvent(intent model.Intent, v model.DataObjectValue)

AppendDataObjectEvent records a data-object write (created or state-changed). Like a variable it carries genuine runtime data (a name, a data state, and a value), so it allocates for its strings — data objects are runtime data, not hot-path token movement (ADR-0053). The event is keyed by the owning scope.

func (*ProcessingContext) AppendDecisionEvaluationEvent

func (c *ProcessingContext) AppendDecisionEvaluationEvent(v model.DecisionEvaluationValue)

AppendDecisionEvaluationEvent records how a business rule task's decision was made — its inputs, outputs, and trace — as append-only history (ADR-0066). The worker evaluated the decision off the processor goroutine and froze the result onto the completion command; this event carries genuine runtime data (JSON payloads), so it allocates for its strings, not hot-path token movement. It is keyed by the owning process instance, so a scope-wide scan yields every decision an instance evaluated in order.

func (*ProcessingContext) AppendElementCommand

func (c *ProcessingContext) AppendElementCommand(key uint64, intent model.Intent, v model.ElementInstanceValue)

AppendElementCommand schedules an element-instance command for a later batch.

func (*ProcessingContext) AppendElementEvent

func (c *ProcessingContext) AppendElementEvent(key uint64, intent model.Intent, v model.ElementInstanceValue)

AppendElementEvent records an element-instance lifecycle fact.

func (*ProcessingContext) AppendInboundDeliveryEvent

func (c *ProcessingContext) AppendInboundDeliveryEvent(v model.InboundDeliveryValue)

AppendInboundDeliveryEvent advances an external source's inbound high-water mark (ADR-0075), keyed on the receiving definition space as a neutral key (the record carries the source id and sequence it needs). Emitted in the same batch as the message publish it guards, so the dedup mark and the effects it authorizes commit atomically under one fsync (invariant I2).

func (*ProcessingContext) AppendIncidentEvent

func (c *ProcessingContext) AppendIncidentEvent(intent model.Intent, v model.IncidentValue)

AppendIncidentEvent records an incident lifecycle fact (created or resolved). The key is the element instance the incident is attached to, and the value carries that key too, so applyToState can locate the index entry from the event alone on either intent (ADR-0061).

func (*ProcessingContext) AppendJobEvent

func (c *ProcessingContext) AppendJobEvent(key uint64, intent model.Intent, v model.JobValue)

AppendJobEvent records a job lifecycle fact.

func (*ProcessingContext) AppendMessageEvent added in v0.12.0

func (c *ProcessingContext) AppendMessageEvent(key uint64, intent model.Intent, v model.MessageValue)

appendEvent writes an event into the batch AND mutates state from that same record via applyToState. Doing both from one record is what keeps the log and state in lockstep — recovery replays the exact same applyToState. AppendMessageEvent appends a message-buffer event (ADR-0370), keyed by the message's own key.

func (*ProcessingContext) AppendMessageFlowEvent

func (c *ProcessingContext) AppendMessageFlowEvent(v model.MessageFlowValue)

AppendMessageFlowEvent retains one delivered message flow as history for the collaboration replay (ADR-0038). It is keyed by its receiving definition (the state index leads with it); the event's header timestamp and position order it on the replay timeline. Emitted once per correlated catch event and once per message-start instantiation, so both kinds of cross-pool delivery are recorded.

func (*ProcessingContext) AppendMessageSubscriptionEvent

func (c *ProcessingContext) AppendMessageSubscriptionEvent(key uint64, intent model.Intent, v model.MessageSubscriptionValue)

AppendMessageSubscriptionEvent records a message-subscription fact (created or correlated). The key is the waiting element instance's key, and the value carries the match pair, so applyToState can locate the index entry from the event alone (invariant I4).

func (*ProcessingContext) AppendMigrationEvent added in v0.3.0

func (c *ProcessingContext) AppendMigrationEvent(v model.ProcessMigrationValue)

AppendMigrationEvent rebinds a running instance to another deployed version of its process (ADR-0162). Unlike every other event it describes no single entity's transition: it carries the whole element mapping the fold rewrites the instance's live records through, frozen at command time so replay reproduces the rebinding from the log rather than by re-deriving it (invariants I4/I6).

func (*ProcessingContext) AppendOperatorActionEvent added in v0.3.0

func (c *ProcessingContext) AppendOperatorActionEvent(v model.OperatorActionValue)

AppendOperatorActionEvent records that an operator intervened on a running instance — completing a parked job by hand, say (ADR-0159). Like AppendVariableAuditEvent it is pure history: emitted alongside the events the intervention produces, it freezes who acted and why into the log, so a forced step is never indistinguishable from one the engine drove and replay rebuilds the identical trail (invariant I6).

func (*ProcessingContext) AppendProcessInstanceCommand

func (c *ProcessingContext) AppendProcessInstanceCommand(key uint64, intent model.Intent, v model.ProcessInstanceValue)

AppendProcessInstanceCommand schedules a process-instance command (e.g. the Terminating that cancels a call activity's child) for a later batch — the same command an API cancel enqueues, so the child tears down through the identical path however its termination was triggered (ADR-0076).

func (*ProcessingContext) AppendProcessInstanceEvent

func (c *ProcessingContext) AppendProcessInstanceEvent(key uint64, intent model.Intent, v model.ProcessInstanceValue)

AppendProcessInstanceEvent records a process-instance lifecycle fact.

func (*ProcessingContext) AppendSignalSubscriptionEvent

func (c *ProcessingContext) AppendSignalSubscriptionEvent(key uint64, intent model.Intent, v model.SignalSubscriptionValue)

AppendSignalSubscriptionEvent records a signal-subscription fact (created or correlated). The key is the waiting element instance's key, and the value carries the signal name, so applyToState can locate the index entry from the event alone (invariant I4). A signal reuses the message subscription intents (SubscriptionCreated / SubscriptionCorrelated) over a separate family (ADR-0088).

func (*ProcessingContext) AppendTimerEvent

func (c *ProcessingContext) AppendTimerEvent(key uint64, intent model.Intent, v model.TimerValue)

AppendTimerEvent records a timer lifecycle fact (created or triggered).

func (*ProcessingContext) AppendTriggerReceiptEvent added in v0.8.0

func (c *ProcessingContext) AppendTriggerReceiptEvent(intent model.Intent, v model.TriggerReceiptValue)

AppendTriggerReceiptEvent records a trigger receipt, or with IntentTriggerReceiptsPruned drops the receipts older than v.Cutoff (ADR-0425).

func (*ProcessingContext) AppendVariableAuditEvent

func (c *ProcessingContext) AppendVariableAuditEvent(v model.VariableAuditValue)

AppendVariableAuditEvent records who set a variable from outside the model — an operator override — as append-only audit history (ADR-0098). Like a variable it carries genuine runtime data (an actor, a name, and contents), so it allocates for its strings; it rides only on the non-hot-path variable-modify command, never token movement. It is keyed by the owning process instance, so a scope-wide scan yields every override an instance received in order.

func (*ProcessingContext) AppendVariableEvent

func (c *ProcessingContext) AppendVariableEvent(intent model.Intent, v model.VariableValue) bool

AppendVariableEvent records a variable write and reports whether it happened: a value past the variable budget is refused, with an incident naming it (ADR-0294). Most callers write engine-derived values — a loop index, a counter — which cannot exceed a budget sized for a business record, and they ignore the result. A caller that writes something a model or a worker produced should not.

The value is data (a name and contents), so unlike the graph-derived events this one does allocate for its strings — variables are runtime data, not hot-path token movement.

func (*ProcessingContext) AppendVariableIndexEvent added in v0.7.0

func (c *ProcessingContext) AppendVariableIndexEvent(v model.VariableIndexValue)

AppendVariableIndexEvent corrects one variable's membership in the value index (ADR-0244). It carries no value: the variable holds that, and the whole point is that the value did not change. Emitted only where an instance's declaration can change under it — a migration, or an operator's reindex — one per variable whose membership actually differs, so an instance already in step produces no events at all.

func (*ProcessingContext) ArrivalsOnNode added in v0.6.0

func (c *ProcessingContext) ArrivalsOnNode(procKey, scopeKey uint64, elementId int32) []Arrival

ArrivalsOnNode returns the tokens waiting on the given node in one execution scope, oldest first, each with the flow it arrived on. The order is the index's: element-instance keys ascend with their minting, so oldest-first is what the scan yields, and it is what makes a join's choice of which token to consume both first-in-first-out and a pure function of state.

The result aliases a processor-owned buffer and is valid until the next call.

func (*ProcessingContext) ChildInstancesOf added in v0.5.0

func (c *ProcessingContext) ChildInstancesOf(callElKey uint64) []uint64

ChildInstancesOf returns the live child process instances a call-activity element instance started, from the committed childByParent index (ADR-0076).

It replaced a walk of every live process instance comparing each one's ParentElementInstanceKey. That walk was O(instances) *per call activity torn down*, so cancelling a parent holding many children cost the product of the two — on the single-writer loop, which is every other request's queue as well. The keys are collected before the caller acts on them, as the walk did, so the caller may emit events for each without disturbing the read.

Read through the transaction, so a child activated earlier in this same batch is visible to the teardown. ADR-0238 originally read the committed store here and called that a determinism measure; it is not one. The records this transaction has already applied are a deterministic function of the commands processed so far — replay applies the same records in the same order — so seeing them is as reproducible as not seeing them, and strictly more correct. What the committed view actually produced was a child that outlived the caller cancelled in the batch that created it (ADR-0284).

func (*ProcessingContext) ForEachElementInstance

func (c *ProcessingContext) ForEachElementInstance(procKey uint64, fn func(elKey uint64))

ForEachElementInstance calls fn with the key of every element instance belonging to a process instance, through the in-flight transaction — so it sees element instances created earlier in the same batch, consistently with GetElementInstance, GetJob, and ActiveChildren (all tx-reads). This matters for a terminate end event reached in the same batch as a parallel sibling's activation (ADR-0116): the sibling is not yet committed, but it is in the tx, so the scope teardown finds it. Keys are collected before fn runs so fn may mutate element-instance state (e.g. emit terminations) without disturbing the scan.

func (*ProcessingContext) ForEachStartTimer

func (c *ProcessingContext) ForEachStartTimer(fn func(key uint64, v model.TimerValue))

ForEachStartTimer calls fn with the key and value of every armed start timer, read from the committed timer index. Entries are collected before fn runs so fn may emit timer events (arming/retiring) without disturbing the scan. Used only when a definition is deployed (off the hot path), to arm and supersede start timers (ADR-0051).

func (*ProcessingContext) GetDataObject

func (c *ProcessingContext) GetDataObject(scope uint64, name string) *model.DataObjectValue

GetDataObject reads a scope's data object by name through the in-flight transaction (sees writes from earlier in this batch). A data-output association uses it to keep the object's current value or state when the write changes only one of them (ADR-0058); nil if the object is absent.

func (*ProcessingContext) GetElementInstance

func (c *ProcessingContext) GetElementInstance(key uint64) *model.ElementInstanceValue

GetElementInstance reads element-instance state through the in-flight transaction (sees this batch's uncommitted writes).

func (*ProcessingContext) GetIncident

func (c *ProcessingContext) GetIncident(elKey uint64) *model.IncidentValue

GetIncident reads the incident attached to an element instance through the in-flight transaction, or nil if there is none (ADR-0061).

func (*ProcessingContext) GetJob

func (c *ProcessingContext) GetJob(key uint64) *model.JobValue

GetJob reads job state through the in-flight transaction.

func (*ProcessingContext) GetProcessInstance

func (c *ProcessingContext) GetProcessInstance(key uint64) *model.ProcessInstanceValue

GetProcessInstance reads process-instance state through the in-flight transaction.

func (*ProcessingContext) GetVariable

func (c *ProcessingContext) GetVariable(scope uint64, name string) *model.VariableValue

GetVariable reads a scope's variable by name through the in-flight transaction (sees writes from earlier in this batch, e.g. seeded start variables).

func (*ProcessingContext) IsCanceling

func (c *ProcessingContext) IsCanceling(txKey uint64) bool

IsCanceling reports whether the transaction scope txKey was marked cancelling by a cancel end event (ADR-0108).

func (*ProcessingContext) JobOfElement

func (c *ProcessingContext) JobOfElement(elKey uint64) (uint64, bool)

JobOfElement returns the key of the job held by an element instance and whether it holds one, through the in-flight transaction. An interrupting boundary event uses it to cancel the host activity's job when it terminates the host.

func (*ProcessingContext) NewKey

func (c *ProcessingContext) NewKey() uint64

NewKey mints a fresh entity key. The minted key is frozen into the event that uses it, so replay reproduces it without regeneration (invariant I6).

func (*ProcessingContext) NotifyJobAvailable

func (c *ProcessingContext) NotifyJobAvailable(jobType int32)

NotifyJobAvailable registers a post-fsync notification that a job of the given type is available (invariant I2: runs after the batch is durable).

func (*ProcessingContext) Now

func (c *ProcessingContext) Now() int64

Now reads wall-clock time. It is captured into events here, never inside applyToState (invariant I4).

func (*ProcessingContext) OldestPerFlow added in v0.6.0

func (c *ProcessingContext) OldestPerFlow(arrivals []Arrival) []Arrival

OldestPerFlow reduces arrivals to one token per distinct incoming flow — the oldest on each — which is the set a join firing consumes. Everything it leaves out is surplus: a second token on a flow that already has one, which belongs to the *next* firing and must not be swallowed by this one.

The result aliases a second processor-owned buffer, so it stays valid across a re-scan of the node.

func (*ProcessingContext) ResolveVariable

func (c *ProcessingContext) ResolveVariable(startScope uint64, name string) *model.VariableValue

ResolveVariable reads name resolving up the scope chain from startScope (nearest scope wins), the lookup activity-local scopes and Camunda-style I/O mappings need (ADR-0068). A scope's parent is its element instance's FlowScopeKey; the root process-instance scope has no element instance, which ends the walk. Reads go through the in-flight transaction, so they see this batch's writes.

func (*ProcessingContext) TokenCanStillReach

func (c *ProcessingContext) TokenCanStillReach(procKey, scopeKey uint64, nodeId int32, reaches compiler.NodeSet) bool

TokenCanStillReach reports whether any live token in scopeKey could still arrive at nodeId: an active element instance sitting on a node from which nodeId is reachable (per reaches), or a token in flight as an element-activating command not yet processed — the rest of this batch's queue plus followups generated so far — targeting such a node or nodeId itself. Tokens already parked on nodeId are the join's own arrivals and are excluded. An inclusive join fires only when this is false. Considering in-flight commands is what keeps two pass-through branches from each firing the join separately.

scopeKey scopes the question the same way it scopes a parallel join's count (ADR-0277): a token in a *sibling* iteration of a multi-instance subprocess is on the same node ids but can never arrive here, and letting it hold the join open made every iteration wait for the slowest one.

Narrowing to one scope does not blind the join to a token running inside a nested subprocess on one of its branches: reaches follows sequence flows, which never cross a scope boundary, so an inner node is not in reaches at all — what keeps the join waiting is the subprocess's own element instance, which sits in *this* scope on a node that does reach the join.

func (*ProcessingContext) TokenEntering added in v0.9.2

func (c *ProcessingContext) TokenEntering(scopeKey uint64) bool

TokenEntering reports whether a token is on its way into scopeKey over a sequence flow: an element that completed and took a flow has written its Completed already, and its successor's activation is still a queued command, so the token is in neither place the active-child counter sees (#1013). Only a flow's activation counts — one with SourceFlowId >= 0. An armed boundary, an event-subprocess trigger, a compensation handler or an ad-hoc activity is entered some other way, and none of them is a token a scope waits for in order to drain.

It reads the queue the way ProcessingContext.TokenCanStillReach does, and for the same reason that is safe across a restart: the queue is the batch's continuation, restored on recovery (ADR-0271), so the commands seen here are the ones a resumed processor sees.

func (*ProcessingContext) VariablesOfScope

func (c *ProcessingContext) VariablesOfScope(scope uint64, fn func(v model.VariableValue))

VariablesOfScope calls fn with each variable owned by scope, read through the in-flight transaction (so it sees this batch's writes). Values are collected into a fresh slice before fn runs, so fn may emit variable events (e.g. deleting the scope's locals) without disturbing the underlying scan. Used to drop an activity-local scope on completion (ADR-0068).

type Processor

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

Processor owns one partition's command processing.

func New

func New(partition uint16, log *wal.Log, store *state.Store, clock Clock) *Processor

New creates a processor for the given partition over an open log and store. A nil clock defaults to the system clock.

func (*Processor) ActivateJob added in v0.3.0

func (p *Processor) ActivateJob(jobKey uint64, worker string, leaseFor int64)

ActivateJob enqueues an external worker's claim on a job (ADR-0007): the job is held off the activatable index for leaseFor nanoseconds and recorded as held by worker, so no other worker is offered it while this one works.

The lease is a bound, not a lock. When it elapses the job is offered again — that is what makes a worker crash recoverable without an operator — so a worker that outlives its lease may find its work has been handed on. Activating a job that is gone, or one another worker already holds, is a no-op. Call RunUntilIdle (or Drive) to process it.

func (*Processor) ArmStartTimers

func (p *Processor) ArmStartTimers(defKey uint64)

ArmStartTimers enqueues arming of a freshly deployed definition's timer start events: the handler creates their durable timers and retires any that a prior version of the same process left armed, so only the latest version's schedule is active (ADR-0051). Call it once per *fresh* deploy (not on recovery — the restored TimerCreated events already hold the armed timers), then RunUntilIdle (or Drive) to process it. It scans the armed start timers, so callers skip it for a first-version process with no timer start events (nothing to arm or supersede); a re-version still calls it so a removed schedule is retired.

func (*Processor) AssignJob

func (p *Processor) AssignJob(jobKey uint64, assignee string)

AssignJob enqueues a (re)assignment of a user task's assignee, identified by its job key. A non-empty assignee is a claim; an empty one unclaims the task, making it available again. The job stays open either way. Assigning a job that no longer exists is a no-op. Call RunUntilIdle to process it (ADR-0042).

func (*Processor) CancelInstance

func (p *Processor) CancelInstance(piKey uint64)

CancelInstance enqueues termination of a running process instance: every active element instance is terminated and the instance is recorded as terminated in history (ADR-0017). Any timer/subscription/job the instance left waiting is self-retiring — when it later fires or correlates it finds no element and does nothing. Call RunUntilIdle to process it.

func (*Processor) Checkpoint added in v0.2.0

func (p *Processor) Checkpoint(root string) (uint64, error)

Checkpoint stages and publishes a checkpoint in one call, returning the applied log position it captures.

Both halves run on the calling goroutine, so this is for callers with no writer to keep free — tests, and synchronous embedding. **The server uses Processor.StageCheckpoint** and commits the result off the run loop, because the commit reads the whole state store.

func (*Processor) ClearCallTargetOverride

func (p *Processor) ClearCallTargetOverride(calledProcessId string)

ClearCallTargetOverride removes a called process id's override, restoring the default `latest` resolution. Idempotent. Run-loop goroutine only.

func (*Processor) CompactLog added in v0.2.0

func (p *Processor) CompactLog(checkpointRoot string, consumerLimits []uint64) (int, error)

CompactLog resolves the compaction cut and deletes the WAL segments no longer needed for recovery in one call, returning how many were removed (ADR-0131). Both halves run on the calling goroutine, so this is for callers with no writer to keep free — tests, and synchronous embedding.

**The server splits it**, into Processor.CompactionCut off the run loop and Processor.CompactLogAt on it, because resolving the cut verifies checkpoints and verifying one reads every byte of its state files.

A segment is removed only when it lies entirely at or below the **compaction cut**, which is the minimum of:

  • the newest checkpoint for this partition that **fully verifies** — manifest *and* state files — and whose applied position is at or below the store's. Verification is stricter here than in RecoverFrom on purpose: once the prefix is deleted, that checkpoint's state files become the only way to rebuild it, so a corrupt snapshot must never license a deletion. Requiring it to be at or below the store's applied position matters just as much: recovery refuses a checkpoint ahead of the store (it skips reading a prefix, it does not install state files), so deleting below such a checkpoint would strand recovery with a gap it can no longer replay.
  • every consumerLimit the caller passes — the exported-log high-water mark (ADR-0114) and the retention safe position (ADR-0115) when those are enabled. The caller owns this list because only it knows which consumers exist; passing nil means "no consumers", so pass every enabled consumer's watermark or risk deleting records it has not read yet.

If no checkpoint qualifies the cut is zero and **nothing is deleted** — the log stays the sole recovery source rather than being trimmed on a promise that cannot be checked. Compaction is an optimization like the checkpoint itself: skipping it costs disk, never correctness.

func (*Processor) CompactLogAt added in v0.7.0

func (p *Processor) CompactLogAt(cut uint64) (int, error)

CompactLogAt deletes the WAL segments lying entirely at or below cut and returns how many went. A zero cut deletes nothing.

**It must be called on the single-writer goroutine**: the log belongs to the writer, which may be rolling a segment at the same moment (invariant I3). Unlike resolving the cut, this really is the bounded work the old single call claimed to be — a few unlinks and one directory fsync, for segments already proven redundant.

func (*Processor) CompactionCut added in v0.7.0

func (p *Processor) CompactionCut(root string, lastApplied uint64, consumerLimits []uint64) (uint64, error)

CompactionCut resolves the cut Processor.CompactLogAt may delete up to, or zero when nothing may be deleted. See Processor.CompactLog for what decides it.

**It may run off the single-writer goroutine, and on a large store it should.** Resolving the cut verifies checkpoints, and verifying one reads every byte of its state files — the same whole-store read that made the checkpoint itself too expensive to publish on the writer. Nothing it touches is loop-owned: the partition is fixed at construction, and everything else is the checkpoint directory.

lastApplied is passed in rather than read here for exactly that reason — it is the one loop-owned value the decision needs, so the caller reads it on the writer and resolves the cut off it. A value that has gone stale in between can only make the cut more conservative: it is used to reject checkpoints *ahead* of the store, and a store that has since advanced was never at risk from one it already covers.

func (*Processor) CompleteJob

func (p *Processor) CompleteJob(jobKey uint64, outputs ...model.VariableValue)

CompleteJob enqueues completion of a job by a worker, optionally carrying the output variables the worker produced (e.g. a business rule task's decision result). The outputs are written into the job's process instance scope when the completion is processed, before the element completes, so a downstream gateway can route on them. They are frozen into VariableCreated events, so replay re-applies them without re-running the worker (invariant I6).

func (*Processor) CompleteJobManually added in v0.3.0

func (p *Processor) CompleteJobManually(jobKey uint64, actor, reason string, outputs ...model.VariableValue)

CompleteJobManually completes a job the way a worker would, but on an operator's say-so rather than because the work was reported (ADR-0159): the job is completed exactly as CompleteJob does, and the intervention is additionally frozen into an append-only audit event carrying who forced it and why. actor is the acting principal's username ("" when auth is off); reason is their justification. Use this, never CompleteJob, for anything a person triggers, so a forced step is never indistinguishable from one the engine drove.

func (*Processor) CompleteJobWithDecision

func (p *Processor) CompleteJobWithDecision(jobKey uint64, decision *model.DecisionEvaluationValue, outputs ...model.VariableValue)

CompleteJobWithDecision completes a business rule task's job like CompleteJob, additionally carrying the DMN decision evaluation the worker produced (ADR-0066): its inputs, outputs, and trace, frozen into a history event when the completion is folded so an operator can later inspect how the decision was made. decision may be nil, in which case this behaves exactly like CompleteJob.

func (*Processor) CompleteJobWithOutcome added in v0.9.0

func (p *Processor) CompleteJobWithOutcome(jobKey uint64, outcome model.ActionOutcomeValue, outputs ...model.VariableValue)

CompleteJobWithOutcome completes a shop send task's job carrying how the action its instance carries ended (ADR-0429 §4). The handler that produced it runs off the loop, so it does not write the outcome; handleJobCompleted appends it in the batch that completes the job, so the step and the fact commit together (I2). An outcome the command already has with a different ending is not written: the first stands.

func (*Processor) CompleteJobWithToolCalls added in v0.5.0

func (p *Processor) CompleteJobWithToolCalls(jobKey uint64, toolCalls []model.ToolCall, outputs ...model.VariableValue)

CompleteJobWithToolCalls completes an agent-driven ad-hoc subprocess's round job (ADR-0253), carrying the tools the model chose to run next. An empty or nil toolCalls is the agent reporting it is done: the container then completes through the ordinary path, exactly as CompleteJob would drive it. Any other job type ignores the calls, so this is only meaningful on a container's round job.

func (*Processor) CreateInstance

func (p *Processor) CreateInstance(defKey uint64, startVars ...model.VariableValue)

CreateInstance enqueues creation of a new instance of the given definition, optionally seeded with initial variables. Call RunUntilIdle to process it.

func (*Processor) CreateInstanceReporting added in v0.7.0

func (p *Processor) CreateInstanceReporting(defKey uint64, created *uint64, startVars ...model.VariableValue)

CreateInstanceReporting is Processor.CreateInstance for a caller that needs the new instance's key: it is written to *created when the command is processed, and left untouched when no instance was created. Read it only after RunUntilIdle returned without error.

func (*Processor) CreateInstanceStartedBy added in v0.20.0

func (p *Processor) CreateInstanceStartedBy(defKey uint64, created *uint64, startedBy string, startVars ...model.VariableValue)

CreateInstanceStartedBy is Processor.CreateInstanceReporting for a start an authenticated principal asked for: startedBy, their stable principal id, rides on the creation command's instance value, which the activation event copies whole, so who initiated the instance is durable in the same fsync as the instance and read back on replay (I2, I6) — the trusted "initiated by" of ADR-0475 §3.

func (*Processor) CreateInstanceWithPass added in v0.10.0

func (p *Processor) CreateInstanceWithPass(defKey uint64, created *uint64, passHash string, startVars ...model.VariableValue)

CreateInstanceWithPass is Processor.CreateInstanceReporting for the public start of a process that holds a public wizard (ADR-0449). passHash is the SHA-256, hex, of the pass the start hands its visitor. It rides on the creation command's own instance value, which the activation event copies whole, so the hash is durable in the same fsync as the instance and read back on replay rather than recomputed (I2, I6), and applyToState stores it with the rest of the record unchanged (I4).

func (*Processor) DeliverMessage added in v0.8.0

func (p *Processor) DeliverMessage(instanceKey uint64, messageName, correlationKey, source, triggerID string, result *DeliveryResult, vars ...model.VariableValue)

DeliverMessage enqueues a directed delivery: hand the message messageName, under correlationKey, to the running instance instanceKey only, writing vars into its scope. source and triggerID identify the delivery; a non-empty triggerID makes it idempotent per source. The answer is written to *result once RunUntilIdle returned without error.

func (*Processor) Deploy

func (p *Processor) Deploy(cp *compiler.CompiledProcess)

func (*Processor) FailJob

func (p *Processor) FailJob(jobKey uint64, retries int32, message string, backoff int64)

FailJob enqueues a worker's failure report for a job (ADR-0061), carrying the retries the worker leaves it, a failure message, and a retry backoff (unix-nanoseconds; 0 = retry immediately, ADR-0111). With retries > 0 the job is retried — immediately if backoff is 0, otherwise held off the activatable index until a retry timer fires backoff nanoseconds later; with retries <= 0 an incident is raised on the job's element and the token parks there. Failing a job that no longer exists is a no-op. Call RunUntilIdle (or Drive) to process it.

func (*Processor) ForkInstance added in v0.7.0

func (p *Processor) ForkInstance(piKey, targetDefKey uint64, resume []int32, actor, reason string)

ForkInstance enqueues the fork of a running instance onto another deployed version of its process (ADR-0389): the instance is ended where it is and its work continues in a *new* instance of that version, seeded at the resume elements given, carrying its root-scope variables and data objects, with each record naming the other.

It is what an operator reaches for when ValidateMigration refused a rebinding — a token on an element the target version no longer has cannot be carried across, but the instance's data and a decision about where the work picks up again can. resume names elements by their index in the *target* version; the caller resolves them from BPMN ids, because no model string belongs in the log (invariant I5).

The caller validates first — it holds both compiled processes — and the handler re-checks on the run loop, because the instance is free to move in between. A fork that no longer holds is dropped; the caller's refusal is the one an operator reads. Call RunUntilIdle to process it.

func (*Processor) GrantEntitlement added in v0.7.0

func (p *Processor) GrantEntitlement(v model.EntitlementValue)

GrantEntitlement enqueues the fact that a principal now holds an item. The moment travels in the value, read by the caller at command time and frozen into the event, so replay reproduces it rather than re-reading a clock (I4/I6).

Granting something already held replaces it, which is how a re-grant after a revocation reads: one entitlement with a new start, rather than two overlapping ones nobody can subtract.

func (*Processor) GrantEntitlementWithOutcome added in v0.9.0

func (p *Processor) GrantEntitlementWithOutcome(v model.EntitlementValue, outcome model.ActionOutcomeValue)

GrantEntitlementWithOutcome is GrantEntitlement for a grant that ends a provision: the grant and the provision's outcome are appended by one handler, so one fsync commits both or neither (I2).

func (*Processor) Halted added in v0.20.0

func (p *Processor) Halted() error

Halted reports why the engine stopped processing, or nil while it runs. It is the one Processor method safe to call from any goroutine: the HTTP layer and the storage monitor ask it from outside the run loop to refuse writes up front and to say on the dashboard that a restart is needed.

func (*Processor) HasApplicationConstant added in v0.13.0

func (p *Processor) HasApplicationConstant(defKey uint64, name string) bool

HasApplicationConstant reports whether the application a definition is filed under holds name on this server — what an instance created now would be seeded with. Run-loop goroutine only; the server layer asks it before it lets a person start a definition whose bound constant has no fallback.

func (*Processor) HasServerConstant added in v0.13.0

func (p *Processor) HasServerConstant(name string) bool

HasServerConstant reports whether this installation holds the server constant name. Run-loop goroutine only, for the same refusal.

func (*Processor) LastRecovery added in v0.2.0

func (p *Processor) LastRecovery() RecoveryStats

LastRecovery returns what the last Recover/RecoverFrom did.

It is read at scrape time rather than pushed, which is what keeps it simple: recovery happens once, before the server that would hold a metrics registry exists, so a pushed counter would have nowhere to go. The fields are written by the goroutine that runs recovery and read only after it returns, so the construction that follows establishes the happens-before (invariant I3 is untouched — this never reaches partition state).

func (*Processor) MigrateInstance added in v0.3.0

func (p *Processor) MigrateInstance(v model.ProcessMigrationValue, actor, reason string)

MigrateInstance enqueues the rebinding of a running instance from one deployed version of its process to another (ADR-0162), carrying the fully materialized element mapping the fold will rewrite its live records through, plus who asked and why.

The mapping is built and validated by the caller — it needs both compiled processes and the deployment records, which the API holds — and re-checked here on the run loop before anything is emitted, because the instance is free to move in between. A migration that no longer holds is dropped; the caller's refusal is the one an operator reads. Call RunUntilIdle to process it.

func (*Processor) Partition added in v0.5.0

func (p *Processor) Partition() uint16

Deploy registers an immutable compiled definition so instances can run it, and indexes any message start events so a correlating message instantiates it (ADR-0035). Partition reports which partition this processor drives. It is read-only and fixed for the processor's life, so it is safe to call from any goroutine — the API's node descriptor (ADR-0189 §6) reads it while serving a request, off the run loop.

func (*Processor) ProcessActive added in v0.2.0

func (p *Processor) ProcessActive(defKey uint64) bool

ProcessActive reports whether a definition may auto-start new instances — the inverse of the ADR-0119 deactivation flag. A key that was never deactivated (the default) is active. Run-loop goroutine only.

func (*Processor) PruneEventLog added in v0.20.0

func (p *Processor) PruneEventLog(through uint64)

PruneEventLog enqueues dropping every event-log row of this partition at or before through, a log position (ADR-0472 §4). The cut is a fact, as the event feed's is (feed.go): the event carries it and applyToState drops the rows, live and on replay alike.

func (*Processor) PruneFeed added in v0.9.0

func (p *Processor) PruneFeed(through uint64)

PruneFeed enqueues dropping every feed row of this partition at or before through, a log position.

func (*Processor) PruneTriggerReceipts added in v0.8.0

func (p *Processor) PruneTriggerReceipts(cutoff int64)

PruneTriggerReceipts enqueues dropping every receipt received before cutoff (Unix nanoseconds). A retry that arrives after its receipt is gone is a new trigger.

func (*Processor) PublishInbound

func (p *Processor) PublishInbound(sourceID string, seq uint64, name, correlationKey string, vars ...model.VariableValue)

PublishInbound enqueues publication of a message that originated from an external event source (ADR-0075), carrying the source's identity (sourceID) and monotonic sequence (seq) so the publish is deduplicated against the source's durable high-water mark: a replayed at-least-once delivery is skipped rather than re-correlated (which would double-start a message-start process). Apart from the dedup guard it correlates exactly like PublishMessage. Call RunUntilIdle to process it.

func (*Processor) PublishMessage

func (p *Processor) PublishMessage(name, correlationKey string, vars ...model.VariableValue)

PublishMessage enqueues publication of a message with the given name and correlation key, optionally carrying payload variables that are written into every correlated instance's scope. It correlates against open subscriptions through the same path a message throw event uses; a message that matches no subscription is a no-op (no buffering yet, ADR-0020). Call RunUntilIdle to process it.

func (*Processor) PublishMessageWithTTL added in v0.12.0

func (p *Processor) PublishMessageWithTTL(name, correlationKey, messageID string, ttl time.Duration, vars ...model.VariableValue)

PublishMessageWithTTL enqueues publication of a message that is kept when nothing waits for it yet (ADR-0370): if it correlates no subscription and starts no instance, it is buffered for ttl, and the first subscription that opens on its name and key in that time receives it. messageID, when not empty, makes a repeat of the message — the same name, key and id — a no-op for as long as the first one lives, delivered or not. A ttl of zero is PublishMessage. Call RunUntilIdle to process it.

func (*Processor) PurgeInstance added in v0.2.0

func (p *Processor) PurgeInstance(piKey uint64, pi *model.ProcessInstanceValue)

PurgeInstance enqueues the hard delete of a finished instance's history (ADR-0115): its terminal record and every per-instance family are removed from the state store through a durable IntentPurged event, so the deletion replays on recovery. The retention sweep calls it for an instance it has already read from the history index and gated on age + exported position; the carried value supplies the definition key the cleanup needs. Purging an instance that is not (or no longer) in history is a harmless no-op — the deletes are idempotent. Call RunUntilIdle to process it.

func (*Processor) RecordApprovalAnswer added in v0.20.0

func (p *Processor) RecordApprovalAnswer(v model.ActionApprovalValue, result *ApprovalResult)

RecordApprovalAnswer enqueues an approver's answer (Kind ApprovalDecided, with an Outcome) or the withdrawal of one (Kind ApprovalRevoked) for the request v.ApprovalKey names in instance v.ProcessInstanceKey. Who may answer — the approver group, separation of duties — is the caller's check, against the user store the engine does not read; this checks what only the log knows: that the request exists and is open, and what this principal has already said. v.At is the caller's clock.

func (*Processor) RecordAuthorization added in v0.20.0

func (p *Processor) RecordAuthorization(v model.AuthorizationValue, approval *model.ActionApprovalValue, message string, result *AuthorizationResult)

RecordAuthorization enqueues a decision about the job v names, under the lease v names. For an enforced refusal, approval non-nil asks for that approval and throws ApprovalRequiredErrorCode; otherwise the job fails with its retries spent, under an incident carrying message. A permit, a shadow decision and a stale lease change nothing but the record. The answer is written to *result once RunUntilIdle returned.

func (*Processor) Recover

func (p *Processor) Recover() error

Recover rebuilds in-memory position/key state and catches the store up to the log. It replays events after the store's last applied position through the same applyToState used live (invariant I4), and restores the key counter and log position from what the log already froze (invariant I6). Call once after New, before processing.

func (*Processor) RecoverFrom added in v0.2.0

func (p *Processor) RecoverFrom(checkpointRoot string) error

RecoverFrom is Recover with a recovery-checkpoint root (ADR-0131). When the root holds a checkpoint this processor may skip past, replay starts after the position that checkpoint covers instead of at genesis, and the highest log position and key counter it recorded seed what the skipped prefix would have contributed.

An empty root, or no usable checkpoint, replays the whole log exactly as before: falling back is always correct, only slower, so a missing, corrupt, foreign, or too-new checkpoint can never produce wrong state (invariant I2 is untouched — the WAL remains the source of truth).

func (*Processor) ReindexInstanceVariables added in v0.7.0

func (p *Processor) ReindexInstanceVariables(piKey uint64)

ReindexInstanceVariables enqueues a repair of one instance's variable-index membership: the handler compares the instance's root-scope variables against what its own process declares searchable (ADR-0244) and emits a membership event for each one that differs. An instance already in step produces no events, so the command is idempotent and a repair run over a whole version costs one comparison per variable the second time.

It exists for the instances a migration reached before migration itself corrected membership. Nothing about it is time- or definition-derived at fold time: the comparison happens here, on the run loop, and only its answer reaches the log (invariant I6). Call RunUntilIdle to process it.

func (*Processor) ReportActionOutcome added in v0.9.0

func (p *Processor) ReportActionOutcome(v model.ActionOutcomeValue, result *OutcomeResult)

ReportActionOutcome enqueues one report of how an action ended. The moment travels in the value, read by the caller at command time and frozen into the event (I4/I6). The answer is written to *result once RunUntilIdle returned.

func (*Processor) ResolveIncident

func (p *Processor) ResolveIncident(elementKey uint64, retries int32)

ResolveIncident enqueues an operator's resolution of the incident attached to elementKey (ADR-0061): the incident is cleared and its job re-created with retries (>= 1), returning it to the activatable index so a worker retries it. Resolving an incident that no longer exists is a no-op. Call RunUntilIdle (or Drive) to process it.

func (*Processor) RevokeEntitlement added in v0.7.0

func (p *Processor) RevokeEntitlement(principal, itemID string, at int64,
	reason model.HoldEnd, by string)

RevokeEntitlement enqueues the fact that a principal no longer holds an item. Revoking something nobody was recorded as holding is a no-op rather than an error: it is the state the caller asked for, and refusing it would make a reconciliation that removes a privilege twice into a failure.

The moment and the reason travel in the value, read by the caller at command time and frozen into the event, so replay reproduces them rather than re-reading a clock or a request (I4/I6). Everything else about the hold that is ending — when it began, what it was ordered under, when it was meant to end — is deliberately *not* carried: it is already in state, and reading it where the event is folded is what makes a double revocation write one history row instead of two (ADR-0346).

The value is an model.EntitlementHistoryValue with those three fields set and the rest left to the fold. A revocation and a hold are different facts, and the event that ends a hold says so in its type.

func (*Processor) RevokeEntitlementWithOutcome added in v0.9.0

func (p *Processor) RevokeEntitlementWithOutcome(principal, itemID string, at int64,
	reason model.HoldEnd, by string, outcome model.ActionOutcomeValue)

RevokeEntitlementWithOutcome is RevokeEntitlement for a revocation that ends a return, with the return's outcome in the same batch.

func (*Processor) RunUntilIdle

func (p *Processor) RunUntilIdle() error

RunUntilIdle processes batches until the queue (including generated followups) drains. Deterministic and synchronous — the basis for tests and simple embedding; the channel-driven concurrent loop arrives with the API milestone.

func (*Processor) SetApplicationConstants added in v0.13.0

func (p *Processor) SetApplicationConstants(applicationID string, constants map[string]ConstantValue)

SetApplicationConstants replaces the constants an application holds on this server; nil or empty removes them. The map is the processor's from here on — the caller must not modify it. Run-loop goroutine only: the server layer calls it at startup, when the constants are saved, and when the application is deleted. Every cached application namespace is dropped: the change is an operator's, rare, and the next start of each definition rebuilds its own.

func (*Processor) SetApplicationInfo added in v0.13.0

func (p *Processor) SetApplicationInfo(applicationID string, info ApplicationInfo)

SetApplicationInfo records what the application namespace says about an application; the zero value removes it. Run-loop goroutine only: at startup, and when an application is created, renamed or deleted.

func (*Processor) SetCallTargetOverride

func (p *Processor) SetCallTargetOverride(calledProcessId string, ov CallTargetOverride)

SetCallTargetOverride installs (or replaces) the per-server override for a called process id. Must be called on the run-loop goroutine (the map's single owner): the server layer calls it at startup and on an admin change (ADR-0105).

func (*Processor) SetDefinitionApplication added in v0.12.0

func (p *Processor) SetDefinitionApplication(defKey uint64, applicationID string)

SetDefinitionApplication records which application a deployed definition is filed under on this server; "" means none. Run-loop goroutine only: the server layer calls it at startup, on deploy, and when a definition moves between applications.

func (*Processor) SetExecutionBudget added in v0.5.0

func (p *Processor) SetExecutionBudget(steps int32)

SetExecutionBudget sets how many steps one token may take in a single run. A value of zero or less restores DefaultExecutionBudget; there is deliberately no way to turn the budget off, because "off" is the behaviour this exists to remove.

func (*Processor) SetJobNotifier

func (p *Processor) SetJobNotifier(fn func(jobType int32))

SetJobNotifier installs the hook the service-task behavior triggers (after fsync) when a job of a type becomes available.

func (*Processor) SetMaxCollection added in v0.6.0

func (p *Processor) SetMaxCollection(n int64)

SetMaxCollection sets how large an output collection may be. Zero or less restores DefaultMaxCollection.

func (*Processor) SetMaxIterations added in v0.5.0

func (p *Processor) SetMaxIterations(n int)

SetMaxIterations sets how many iterations one multi-instance activity may ask for. Zero or less restores DefaultMaxIterations.

func (*Processor) SetMaxVariable added in v0.6.0

func (p *Processor) SetMaxVariable(n int64)

SetMaxVariable sets how large one variable's value may be. Zero or less restores DefaultMaxVariable; as with every budget here there is no way to turn it off.

func (*Processor) SetMetrics added in v0.2.0

func (p *Processor) SetMetrics(m Metrics)

SetMetrics attaches batch instrumentation, or detaches it with nil. Call it before the processor starts handling commands; like SetJobNotifier it is not safe to change while batches are running.

func (*Processor) SetProcessActive added in v0.2.0

func (p *Processor) SetProcessActive(defKey uint64, active bool)

SetProcessActive marks a deployed definition active or inactive (ADR-0119). An inactive definition does not auto-start new instances when its timer, message, or signal start events fire; existing instances run to completion, and an explicit operator/API start is unaffected. The server layer loads the flag from the deployment sidecar at startup and calls this on an operator toggle. Like SetCallTargetOverride it is operator config, not event-sourced: it changes only the live decision to schedule a create, so replay is unaffected (I6). Run-loop goroutine only (the map's single owner).

func (*Processor) SetServerConstants added in v0.13.0

func (p *Processor) SetServerConstants(constants map[string]ConstantValue)

SetServerConstants replaces the constants this installation holds for every application; nil or empty removes them. Ownership and goroutine as for SetApplicationConstants.

func (*Processor) SetServerInfo added in v0.13.0

func (p *Processor) SetServerInfo(info ServerInfo)

SetServerInfo records the node identity the server namespace reports. Run-loop goroutine only: at startup and when an operator names the node.

func (*Processor) SetVariables

func (p *Processor) SetVariables(piKey, scopeKey uint64, actor string, vars ...model.VariableValue)

SetVariables enqueues an external, operator-initiated write of variables onto a running instance's scope (ADR-0095): each variable is created if its name is new in the target scope or overwritten if it already exists. piKey is the process instance; scopeKey is the scope the variables land in — pass piKey (or 0, which the handler treats as piKey) for the instance root scope, or a live element instance key belonging to piKey for a subprocess/multi-instance-body local scope. The writes are frozen into VariableCreated/VariableUpdated events, so they replay without re-running this command (invariant I6) and appear in the instance's variable timeline as the audit trail. Setting variables on an instance that is gone (finished or never existed), or on a scope that does not belong to it, is a no-op. It does not re-evaluate any gateway a token has already passed — it only changes the stored values. Each variable set is additionally recorded as an audit event naming actor — who made the change (ADR-0098) — so the "who changed it" trail is durable; pass "" when the caller is unidentified. Call RunUntilIdle (or Drive) to process it.

func (*Processor) StageCheckpoint added in v0.7.0

func (p *Processor) StageCheckpoint(root string) (*checkpoint.Staged, error)

StageCheckpoint snapshots the currently applied state under root and returns the staged checkpoint, which the caller publishes with checkpoint.Staged.Commit (ADR-0131).

It **must be called on the partition's single-writer goroutine, between batches** (invariant I3). That is what makes the checkpoint's consistency boundary exact: no state mutation can race the snapshot, so the position it records is precisely the position the snapshotted state contains. Calling it concurrently with the run loop would produce a snapshot at a fuzzy position — the failure ADR-0131 rejects.

Commit, by contrast, must **not** be called there. It reads every byte of the snapshot to checksum it, so committing on the writer stops command processing for as long as that read takes — which grows with the store and, on a large one, is seconds. Staging here and committing off the loop is the whole reason the two are separate calls; see checkpoint.Staged.

It is purely additive to durability (invariant I2): a checkpoint is an optimization that lets a later recovery replay only the WAL suffix past its applied position. Nothing here writes to the log, mutates state, or acknowledges anything, so a failed or absent checkpoint costs only a slower recovery, never correctness — the caller may log the error and retry on the next cadence.

func (*Processor) ThrowJobError

func (p *Processor) ThrowJobError(jobKey uint64, errorCode string)

ThrowJobError enqueues a worker's report that its job threw a BPMN error code (ADR-0089) — the "throw BPMN error" verb, a sibling of FailJob. Instead of retrying or raising an incident, the handler cancels the job and propagates the error from the job's element to the nearest matching error boundary or error event subprocess. An error with nowhere to go keeps the job, its retries spent, under a job incident, so resolving it retries the job. The code rides in the command's incident.Message field, a transient command carrier that is never persisted. Throwing on a job that no longer exists is a no-op. Call RunUntilIdle (or Drive) to process it.

func (*Processor) ThrowJobErrorManually added in v0.10.0

func (p *Processor) ThrowJobErrorManually(jobKey uint64, errorCode, message, actor, reason string)

ThrowJobErrorManually throws a BPMN error from a parked job on an operator's say-so rather than a worker's report (ADR-0089, ADR-0159): the throw runs exactly as ThrowJobErrorWithMessage does, and the intervention is additionally frozen into an append-only audit event carrying who forced it, why, and the code. actor is the acting principal's username ("" when auth is off); reason is their justification.

func (*Processor) ThrowJobErrorWithMessage added in v0.10.0

func (p *Processor) ThrowJobErrorWithMessage(jobKey uint64, errorCode, message string)

ThrowJobErrorWithMessage is ThrowJobError with the worker's own words about the error: nothing reads them while a handler catches it, and when nothing does they follow the code on the incident an operator reads.

func (*Processor) TickTimers

func (p *Processor) TickTimers() error

TickTimers fires all due timers, drops the buffered messages whose time to live has passed, and processes the resulting work to idle. A server scheduler calls it on the partition's goroutine (invariant I3).

func (*Processor) TriggerDueMessageExpiries added in v0.12.0

func (p *Processor) TriggerDueMessageExpiries() error

TriggerDueMessageExpiries enqueues an expiry command for every buffered message whose time to live has passed by the current clock (ADR-0370). Like the timers it is time-driven and off the command path; the command it enqueues is what drops the message, as an event, so applyToState never reads the clock (I4).

func (*Processor) TriggerDueTimers

func (p *Processor) TriggerDueTimers() error

TriggerDueTimers enqueues a trigger command for every timer due at or before the current clock, carrying each timer's value so the handler needs no extra read. Call RunUntilIdle (or TickTimers) to process them. It is time-driven, so it belongs off the command path — a scheduler calls it periodically.

func (*Processor) TriggerStart added in v0.8.0

func (p *Processor) TriggerStart(defKey uint64, messageName, source, triggerID string, result *TriggerResult, vars ...model.VariableValue)

TriggerStart enqueues a directed trigger: start defKey at its message start event named messageName, seeded with vars. source and triggerID identify the delivery; a non-empty triggerID makes it idempotent per source. The answer is written to *result once RunUntilIdle returned without error.

func (*Processor) Undeploy

func (p *Processor) Undeploy(defKey uint64)

Undeploy removes a definition so no new instances of it can be created, dropping its message-start index entries too. It is the caller's responsibility not to undeploy a definition with running instances (they resolve their definition by key on every batch).

type RecoveryStats added in v0.2.0

type RecoveryStats struct {
	Seconds  float64
	Replayed int
	// Done is false on a processor that has not recovered yet, so a reader can tell
	// "no recovery" from "a recovery that read nothing".
	Done bool
}

RecoveryStats is what the last recovery did: how long it took and how many records it read from the log. It answers the question a restart raises — "how long was this down, and why?" — and, alongside the checkpoint gauges (ADR-0131), whether the checkpoint cadence is actually shortening replay.

Replayed counts records *read*, not events applied: a record at or below the store's applied position is skipped rather than folded in, and a checkpoint lets recovery skip whole segments without reading them at all. That is the number the cadence changes.

type ServerInfo added in v0.13.0

type ServerInfo struct {
	ID          string
	Name        string
	Environment string
}

ServerInfo is what the server namespace says about the installation an instance starts on: its node identity (ADR-0189 §6). Empty fields are facts not set here.

type SystemClock

type SystemClock struct{}

SystemClock reads the host clock.

func (SystemClock) Now

func (SystemClock) Now() int64

type TriggerOutcome added in v0.8.0

type TriggerOutcome uint8

TriggerOutcome is what a directed trigger did.

const (
	// TriggerNotProcessed is the zero value: the command never ran.
	TriggerNotProcessed TriggerOutcome = iota
	// TriggerCreated: a new instance was started at the named start event.
	TriggerCreated
	// TriggerReplayed: this sender delivered this trigger id before; the answer is
	// the instance that answered then, and nothing was started now.
	TriggerReplayed
	// TriggerSingletonTaken: the start event is a singleton (ADR-0094) and an
	// instance for the same correlation key is still live.
	TriggerSingletonTaken
	// TriggerNoSuchStart: the definition is not the newest deployed version of its
	// process, or has no message start event of that name.
	TriggerNoSuchStart
	// TriggerInactive: the definition is deactivated (ADR-0119).
	TriggerInactive
)

type TriggerResult added in v0.8.0

type TriggerResult struct {
	Outcome     TriggerOutcome
	InstanceKey uint64
}

TriggerResult is written through Command.Triggered.

Jump to

Keyboard shortcuts

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