trigger

package
v0.6.0 Latest Latest
Warning

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

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

Documentation

Overview

Package trigger starts runs, whatever asked for them, and arms what a workflow declares under on.

"Five ways in, one path. Every trigger kind creates its run the same way": a person at a client, a schedule coming round, a webhook arriving, an event published and a workflow calling another are each authenticated and authorised where they arrive, and then take Start, which resolves the ref to a commit, binds the inputs against that version's declaration, writes the run and tells the controller, in one transaction that records the run.trigger entry last. So a trigger kind added later is quota-limited, attributed and audited with no code of its own, and a rule about starting a run is one rule rather than one per kind.

Index

Constants

View Source
const InputsMaxBytes = agk.DefaultEnvelopeMaxBytes

InputsMaxBytes is what a run's inputs may weigh: one envelope, envelope_max_bytes at its default, since an input reaches a step as the envelope of a port it feeds.

View Source
const InputsMaxValues = agk.DefaultMaxItems

InputsMaxValues is how many values the inputs of a run may hold, counting every object, array, string, number, boolean and null at any depth, and it is max_items at its default.

Counted as well as weighed, because whoever decodes the inputs pays for their values rather than their bytes, a map for three bytes of {}, and the controller decodes them at every decision it takes on the run. An envelope is what the documentation lets the controller read, and max_items is how many items one carries: inputs held to that many values cost the controller no more than an envelope it may already read.

Variables

View Source
var Draw = func(jitter time.Duration) time.Duration {
	if jitter <= 0 {
		return 0
	}
	return rand.N(jitter + 1)
}

Draw is the jitter a schedule's occurrence is delayed by, at most its jitter: "each occurrence starts up to 5m late", so that schedules written on the hour do not arrive as one burst. Drawn once, when the occurrence becomes the next, and kept on the trigger's row, so that a failover neither draws again nor fires it twice. A variable so that a test can hold it still.

View Source
var ErrCommitAndRef = errors.New("the request names a commit and a ref, and a run is of one commit: name the commit, or the ref the installation resolves to one")

ErrCommitAndRef is a request naming a commit and a ref, where a run is of one commit.

View Source
var ErrDeclarationRefused = errors.New("the version's declaration of its inputs does not compile")

ErrDeclarationRefused is a version whose own declaration of its inputs does not compile, which a push refuses, so that only a version pushed before then holds one. Nothing a request changes would start it.

View Source
var ErrNoObjectStore = errors.New("this installation has no object store attached, and an input's schema names a file of the version's tree, which is kept there")

ErrNoObjectStore is an input's schema naming a file of the version's tree where no object store is attached to read it from.

View Source
var ErrUnarmable = errors.New("the version on the default branch cannot be armed")

ErrUnarmable is a head whose version cannot be armed: one pushed before the rules it is now read by, which it no longer passes. Its triggers are disarmed, and nothing of it fires until a push lands a version that passes.

Functions

func Entries

func Entries(wf *graph.Workflow, namespace string, now time.Time) ([]db.Entry, error)

Entries are the triggers a workflow declares under on, as they are armed in namespace at now: each with what it declares, the values in force written in, a schedule with its next occurrence after now, and an event trigger with the namespace it hears, namespace where the file names none.

func Reconcile

func Reconcile(ctx context.Context, ns *db.NS, workflow, by string, now time.Time) error

Reconcile arms what the default branch's head of workflow declares, in the transaction ns carries, where it is not what the workflow has armed: after a push moved the branch, after the branch was renamed to another, after a tree push recorded the version an unborn branch runs, and at the start of a controller's term for a head nobody armed. by is who moved it, and the entries are armed as at now. A head with nothing to run, or a library's, disarms everything.

It answers a *db.HookTaken where the head arms a webhook another workflow of the namespace holds, and ErrUnarmable, with every trigger of the workflow disarmed and the head recorded as armed with nothing, where the head is a version the rules it is now read by refuse: a caller that commits what it did anyway leaves the workflow firing nothing until a version that passes lands.

func Values

func Values(v any) int

Values counts a decoded document as the API's body reader counts one: every object, array, string, number, boolean and null, at any depth, and the document itself.

Types

type Declaration added in v0.6.0

type Declaration struct {
	Commit string
	Inputs map[string]graph.Input
	Files  map[string]any
}

Declaration is what a manual run of one version takes: the commit a ref resolved to, the inputs that version declares as its file writes them, and each file of its tree their schemas reach by $ref, by its path, as parsed JSON.

type InputsTooLarge

type InputsTooLarge struct{ Why string }

InputsTooLarge is inputs past what a run's inputs may hold once the defaults the workflow declares are in: as many values as one envelope may carry items, and one envelope's weight.

func (*InputsTooLarge) Error

func (e *InputsTooLarge) Error() string

type Options

type Options struct {
	Pool     *db.Pool
	Versions Versions
	Objects  artifact.Objects
	Report   func(error)
	Now      func() time.Time
}

Options are what a Starter reads: the database, the versions, and the object store an input's schema naming a file of the tree is read from. Report hears what failed that was the installation's rather than the caller's; Now is the clock, time.Now where nil.

type Prepared

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

Prepared is a run asked for, with everything read that it is made of: the commit its ref resolved to, its graph and its inputs bound. Nothing is written until Create.

func (Prepared) Commit

func (p Prepared) Commit() string

Commit is the commit the run will be pinned to.

func (Prepared) Create

func (p Prepared) Create(ctx context.Context, ns *db.NS) (agk.RunID, error)

Create writes the run, tells the controller and records run.trigger, in the transaction ns carries, and answers the run: the one place a run is written, so that a trigger added later is quota-limited, attributed and audited with no code of its own. A caller firing a schedule does it in the fenced transaction that moves the schedule on, so that a controller that lost the lead neither starts a run nor records one fired.

type Request

type Request struct {
	Namespace, Workflow string

	// Kind is what asked, and By the principal the run is attributed to: whoever asked, for the
	// kinds somebody asks by, and nobody for a schedule, a webhook or an event, whose runs are the
	// namespace's built-in identity's, which the database writes.
	Kind agk.TriggerKind
	By   string

	// Commit is the version to run, or Ref a branch, a tag or a whole commit resolved to one now,
	// once, or neither, which runs the default branch's head. Both is refused.
	Commit, Ref string

	// Inputs are what was supplied, each number a json.Number as it was written, bound here against
	// the version's declaration with required and default applied. Bound takes their place for a run
	// whose inputs were bound already, a replay's, and is written as it is.
	Inputs map[string]any
	Bound  json.RawMessage

	// ReplayOf and ReplayFrom make the run a replay of another, from a step or from the start.
	ReplayOf   agk.RunID
	ReplayFrom agk.Step

	// Detail is added to what the run.trigger entry records of the run.
	Detail map[string]any

	// Context is what fired the run as expressions read it, frozen on the run: the trigger root,
	// body, headers, query and scheduled_for, and an event trigger's event. A replay is handed the
	// context of the run it replays, so that it sees what fired it and not what is true now.
	Context db.TriggerContext

	// NamespaceVars are the variables the namespace shows the workflow, for a run whose were read
	// already: a replay's, those the run it replays read, so that it reads what that run read and
	// not what is true now; a webhook's or an event's, those its map and its filter read, so that
	// its steps read what they did. Nil, which every other run leaves it, reads them in Create's
	// transaction, the one that writes the run. Either way the run keeps those its file does not
	// write, frozen on it.
	NamespaceVars map[string]any

	// Caller is the step whose call asks for the run, for the kind workflow, and Depth how deep
	// in a chain of calls the run is.
	Caller *db.Caller
	Depth  int
}

Request is one run asked for.

type Started

type Started struct {
	Run    agk.RunID
	Commit string
}

Started is a run created: its identifier and the commit it is pinned to.

type Starter

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

Starter is the one path a run is created by.

func New

func New(o Options) (*Starter, error)

New is a Starter over what o names.

func (*Starter) Declared added in v0.6.0

func (s *Starter) Declared(ctx context.Context, r Request) (Declaration, error)

Declared answers what the run r asks for would take, without asking for it: the ref resolved and the graph read as Prepare reads them, and the declaration compiled against the version's tree as a run binds against it, so that a declaration a run would refuse is refused here too, with the same errors. Nothing is written, and r's inputs are not read.

It is what a form asks before a run is asked for, by whoever may ask for one: the inputs are the workflow's boundary, and nothing else of the file is answered.

func (*Starter) Prepare

func (s *Starter) Prepare(ctx context.Context, r Request) (Prepared, error)

Prepare reads what the run r asks for is made of, and refuses what Start refuses before anything is written. On a refusal the Prepared still names the commit the ref resolved to, where it did.

func (*Starter) Start

func (s *Starter) Start(ctx context.Context, r Request) (Started, error)

Start creates the run r asks for, and answers what it created, or with a refusal the commit its ref resolved to where it resolved: Prepare, then Create in a transaction of its own. What it refuses is one of the errors this package or db names, the caller's to answer: db.ErrNoWorkflow and db.ErrNoVersion for nothing to run, *db.RefUnresolved for a ref naming nothing or two things, version.ErrLibrary for a library, *schema.InputRefusal and *InputsTooLarge for inputs, *db.RunsPerHourReached for the quota, db.ErrWorkflowMoving for a workflow on its way to another namespace, and ErrNoObjectStore for a schema naming a file where no store is attached.

type Versions

type Versions interface {
	Graph(ctx context.Context, namespace, workflow, commit string) (*graph.Graph, error)
}

Versions resolves a workflow's commit to its graph, as version.Store does, and a cache of it.

Jump to

Keyboard shortcuts

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