mihistory

package
v0.22.0 Latest Latest
Warning

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

Go to latest
Published: Nov 3, 2026 License: AGPL-3.0 Imports: 17 Imported by: 0

Documentation

Overview

Package mihistory serves the bounded multi-instance history of a process instance (ADR-0517): the body executions of its multi-instance activities, cursor-paged iterations of one body execution with exact lookup and indexed filters, and one iteration's attributed incidents.

Every read runs on a state.ReadView taken off the single-writer loop (invariant I3, ADR-0080): the service is handed a View that opens one, and has no other way to reach engine state. Every read is a bounded seek in the event-derived MI history index the engine's applyToState maintains; nothing here scans the instance's timeline, builds replay frames or reads variable snapshots, so the cost of a request is independent of how many iterations a body has. The legacy full timeline (GET /api/v1/instances/{key}/timeline) is unchanged.

When the index of this installation is not proven complete (a store that predates it, ADR-0517 "readiness"), every route answers 409 with code "history_unavailable" — never an empty list, which would claim that no iterations ran.

Index

Constants

This section is empty.

Variables

View Source
var ErrLoopClosing = errors.New("server is shutting down")

ErrLoopClosing is what a View returns when the server is shutting down and no read view could be opened.

Functions

This section is empty.

Types

type BodiesResponse

type BodiesResponse struct {
	InstanceKey uint64 `json:"instanceKey"`
	// ProcessDefinitionKey and InstanceState describe the instance itself, so a
	// client can draw its diagram and state without the full timeline.
	ProcessDefinitionKey uint64     `json:"processDefinitionKey"`
	InstanceState        string     `json:"instanceState"`
	ParentIterationKey   uint64     `json:"parentIterationKey,omitempty"`
	HighWaterPosition    uint64     `json:"highWaterPosition"`
	Bodies               []BodyView `json:"bodies"`
	NextCursor           string     `json:"nextCursor,omitempty"`
}

BodiesResponse answers GET /api/v1/instances/{key}/multi-instances.

type BodyResponse

type BodyResponse struct {
	InstanceKey uint64   `json:"instanceKey"`
	Body        BodyView `json:"body"`
}

BodyResponse answers GET /api/v1/instances/{key}/multi-instances/{bodyKey}.

type BodyView

type BodyView struct {
	BodyElementInstanceKey uint64 `json:"bodyElementInstanceKey"`
	ElementID              string `json:"elementId"`
	ProcessDefinitionKey   uint64 `json:"processDefinitionKey"`
	// Mode is "parallel", "sequential" or "loop" (a standard loop) as the
	// definition version that ran the body declares, "unknown" when that
	// version is no longer deployed.
	Mode               string `json:"mode"`
	State              string `json:"state"`
	ActivationPosition uint64 `json:"activationPosition"`
	EndPosition        uint64 `json:"endPosition,omitempty"`
	ParentIterationKey uint64 `json:"parentIterationKey,omitempty"`
	TokenID            uint64 `json:"tokenId"`
	ParentTokenID      uint64 `json:"parentTokenId"`
	// Iterations counts the iterations seeded so far. A sequential body seeds
	// one at a time, so while it runs this is not its planned total; the
	// planned total is not a recorded fact and is not reported.
	Iterations              uint64 `json:"iterations"`
	Active                  uint64 `json:"active"`
	Completed               uint64 `json:"completed"`
	Terminated              uint64 `json:"terminated"`
	IncidentsRaised         uint64 `json:"incidentsRaised"`
	IterationsWithIncidents uint64 `json:"iterationsWithIncidents"`
	// OpenIncidents is set on the single-body route only: incidents attributed
	// to this body that are open now. OpenIncidentsExact is false when more
	// were attributed than one request verifies.
	OpenIncidents      *int  `json:"openIncidents,omitempty"`
	OpenIncidentsExact *bool `json:"openIncidentsExact,omitempty"`
}

BodyView is one multi-instance body execution.

type DecisionView

type DecisionView struct {
	DecisionID         string          `json:"decisionId"`
	ElementInstanceKey uint64          `json:"elementInstanceKey"`
	Position           uint64          `json:"position"`
	At                 int64           `json:"at"`
	DecisionKey        uint64          `json:"decisionKey,omitempty"`
	Inputs             json.RawMessage `json:"inputs"`
	Outputs            json.RawMessage `json:"outputs"`
	// Trace is the rule trace, only with ?technical=true: it is detail for the
	// person who asks for it, not the default reading.
	Trace json.RawMessage `json:"trace,omitempty"`
}

DecisionView is one decision evaluation attributed to an iteration.

type Definitions

type Definitions func(processDefKey uint64) *compiler.CompiledProcess

Definitions resolves a process-definition key to its compiled process, nil when the definition is no longer deployed. It must be safe off the loop.

type IncidentView

type IncidentView struct {
	ElementInstanceKey uint64 `json:"elementInstanceKey"`
	RaisedPosition     uint64 `json:"raisedPosition"`
	EndPosition        uint64 `json:"endPosition,omitempty"`
	// Status: "open" (recorded now), "resolved" (an operator resolved it),
	// "superseded" (a later incident replaced it on the same element), or
	// "cleared" (its element ended while it was open; no resolution recorded).
	Status string `json:"status"`
}

IncidentView is one incident attributed to an iteration or body.

type IterationResponse

type IterationResponse struct {
	InstanceKey        uint64         `json:"instanceKey"`
	Body               BodyView       `json:"body"`
	Iteration          IterationView  `json:"iteration"`
	Incidents          []IncidentView `json:"incidents"`
	IncidentsTruncated bool           `json:"incidentsTruncated"`
	NestedBodies       []BodyView     `json:"nestedBodies"`
	NestedTruncated    bool           `json:"nestedBodiesTruncated"`
	// Variables are the recorded changes of the iteration's own scope, oldest
	// first: its loopCounter and input item as the engine bound them, and what it
	// wrote locally. A contribution to the body's output collection is recorded
	// on the body's collection, not per iteration, and does not appear here.
	Variables          []VariableChange `json:"variables"`
	VariablesTruncated bool             `json:"variablesTruncated"`
	// Decisions are the DMN evaluations attributed to the iteration, with the
	// inputs and outputs the worker froze into the log — never re-evaluated.
	// DecisionsAvailable is false when this store's history predates decision
	// attribution: then an empty list means "not known", not "none".
	Decisions          []DecisionView `json:"decisions"`
	DecisionsAvailable bool           `json:"decisionsAvailable"`
	DecisionsTruncated bool           `json:"decisionsTruncated"`
}

IterationResponse answers .../iterations/{iterationKey}.

type IterationStepsResponse

type IterationStepsResponse struct {
	InstanceKey       uint64            `json:"instanceKey"`
	Body              BodyView          `json:"body"`
	Iteration         IterationView     `json:"iteration"`
	HighWaterPosition uint64            `json:"highWaterPosition"`
	Steps             []OutlineStepView `json:"steps"`
	NextCursor        string            `json:"nextCursor,omitempty"`
}

IterationStepsResponse answers GET /api/v1/instances/{key}/multi-instances/{bodyKey}/iterations/{iterationKey}/steps.

type IterationVariablesResponse

type IterationVariablesResponse struct {
	InstanceKey uint64        `json:"instanceKey"`
	Iteration   IterationView `json:"iteration"`
	At          uint64        `json:"at"`
	Scopes      []StepScope   `json:"scopes"`
	// ScopesTruncated means the iteration ran more steps up to this position than
	// were read to find the scopes open at it.
	ScopesTruncated bool `json:"scopesTruncated,omitempty"`
}

IterationVariablesResponse answers GET .../iterations/{iterationKey}/variables?at=<position>.

type IterationView

type IterationView struct {
	ElementInstanceKey uint64 `json:"elementInstanceKey"`
	// Iteration is the iteration's loopCounter, null when none was recorded.
	Iteration          *uint64 `json:"iteration"`
	State              string  `json:"state"`
	ActivationPosition uint64  `json:"activationPosition"`
	EndPosition        uint64  `json:"endPosition,omitempty"`
	IncidentsRaised    uint64  `json:"incidentsRaised"`
	OpenIncidents      int     `json:"openIncidents"`
	OpenIncidentsExact bool    `json:"openIncidentsExact"`
}

IterationView is one iteration of a body execution.

type IterationsResponse

type IterationsResponse struct {
	InstanceKey       uint64          `json:"instanceKey"`
	Body              BodyView        `json:"body"`
	HighWaterPosition uint64          `json:"highWaterPosition"`
	Iterations        []IterationView `json:"iterations"`
	// NextCursor is set while more matching iterations may follow. A page cut
	// short by the server's per-request work bound can hold fewer rows than
	// the limit, even none, and still carry a cursor.
	NextCursor string `json:"nextCursor,omitempty"`
}

IterationsResponse answers .../multi-instances/{bodyKey}/iterations.

type OutlineResponse

type OutlineResponse struct {
	InstanceKey          uint64            `json:"instanceKey"`
	ProcessDefinitionKey uint64            `json:"processDefinitionKey"`
	InstanceState        string            `json:"instanceState"`
	HighWaterPosition    uint64            `json:"highWaterPosition"`
	Steps                []OutlineStepView `json:"steps"`
	NextCursor           string            `json:"nextCursor,omitempty"`
}

OutlineResponse answers GET /api/v1/instances/{key}/outline.

type OutlineStepView

type OutlineStepView struct {
	Position           uint64 `json:"position"`
	At                 int64  `json:"at"`
	Action             string `json:"action"` // activated, completed, terminated
	ElementID          string `json:"elementId"`
	Type               string `json:"type,omitempty"`
	ElementInstanceKey uint64 `json:"elementInstanceKey"`
	TokenID            uint64 `json:"tokenId"`
	ParentTokenID      uint64 `json:"parentTokenId"`
	// ProcessDefinitionKey is the version the element ran under, as its event
	// recorded it — after a migration not necessarily the instance's current one.
	ProcessDefinitionKey uint64 `json:"processDefinitionKey"`
	// MultiInstanceBody marks a body execution: its iterations are behind it,
	// in the iterations route.
	MultiInstanceBody bool `json:"multiInstanceBody,omitempty"`
	// MultiInstanceIteration marks an iteration's own activation or end, the
	// first and last of its steps.
	MultiInstanceIteration bool `json:"multiInstanceIteration,omitempty"`
}

OutlineStepView is one step of an instance's outline: an element activation or end outside every multi-instance iteration.

type RenderVariable

type RenderVariable func(v *model.VariableValue) (kind, value string)

RenderVariable turns a stored variable into the kind and value an operator reads, exactly as the instance's other variable views render it — an enciphered personal value is named as such, never shown as ciphertext. The server supplies its own renderer so there is one definition of that rule.

type Service

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

Service serves the MI history routes. Build it with New.

func New

func New(view View, now func() time.Time, render RenderVariable) (*Service, error)

New builds the service with a fresh random cursor key. now is the wall clock cursor expiry is measured against; it never reaches engine state.

func (*Service) HandleBodies

func (s *Service) HandleBodies(w http.ResponseWriter, r *http.Request)

HandleBodies serves GET /api/v1/instances/{key}/multi-instances.

func (*Service) HandleBody

func (s *Service) HandleBody(w http.ResponseWriter, r *http.Request)

HandleBody serves GET /api/v1/instances/{key}/multi-instances/{bodyKey}.

func (*Service) HandleIteration

func (s *Service) HandleIteration(w http.ResponseWriter, r *http.Request)

HandleIteration serves GET /api/v1/instances/{key}/multi-instances/{bodyKey}/iterations/{iterationKey}.

func (*Service) HandleIterationSteps

func (s *Service) HandleIterationSteps(w http.ResponseWriter, r *http.Request)

HandleIterationSteps serves the replay window of one iteration: its own activation, every element that ran inside it (a nested body as one step) and its end, in the order they happened, cursor-paged. Nothing else of the instance is read, so its cost does not grow with the iteration count.

func (*Service) HandleIterationVariables

func (s *Service) HandleIterationVariables(w http.ResponseWriter, r *http.Request)

HandleIterationVariables serves the variables of one iteration as they stood at one log position — a step of its replay window: the iteration's own scope and every scope running inside it then, each folded to the latest change per name at or before that position. The body's and the instance's scopes are not folded: their history grows with the iteration count.

func (*Service) HandleIterations

func (s *Service) HandleIterations(w http.ResponseWriter, r *http.Request)

HandleIterations serves GET /api/v1/instances/{key}/multi-instances/{bodyKey}/iterations.

func (*Service) HandleOutline

func (s *Service) HandleOutline(w http.ResponseWriter, r *http.Request)

HandleOutline serves GET /api/v1/instances/{key}/outline: the instance's steps in the order they happened, without the steps inside multi-instance iterations, cursor-paged. It is how a client draws the history of an instance whose full timeline is too large to load.

type StepScope

type StepScope struct {
	ElementInstanceKey uint64         `json:"elementInstanceKey"`
	ElementID          string         `json:"elementId,omitempty"`
	Iteration          bool           `json:"iteration,omitempty"`
	Variables          []StepVariable `json:"variables"`
	// Truncated means the scope holds more changes up to this step than were read,
	// so a variable unchanged since an early change may be missing.
	Truncated bool `json:"truncated,omitempty"`
}

StepScope is one scope of an iteration as it stood at a step: the iteration's own scope, or that of an element running inside it then (a subprocess, a nested body, an activity's local inputs).

type StepVariable

type StepVariable struct {
	Name     string `json:"name"`
	Kind     string `json:"kind"`
	Value    string `json:"value"`
	Position uint64 `json:"position"` // where this value was written
	At       int64  `json:"at"`
	// ValueTruncated means Value holds only the first bytes of a larger value.
	ValueTruncated bool `json:"valueTruncated,omitempty"`
}

StepVariable is one variable as it stood at a step: its latest change at or before the step's log position.

type VariableChange

type VariableChange struct {
	Name        string `json:"name"`
	Kind        string `json:"kind"`
	Value       string `json:"value"`
	Position    uint64 `json:"position"`
	At          int64  `json:"at"`
	ProducerKey uint64 `json:"producerKey,omitempty"`
}

VariableChange is one recorded change of a variable in an iteration's scope.

type View

type View func(fn func(rv *state.ReadView, defs Definitions) error) error

View opens a read view off the single-writer loop, calls fn with it and the deployed definitions, and closes it. fn must not retain either.

Jump to

Keyboard shortcuts

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