script

package
v0.6.0 Latest Latest
Warning

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

Go to latest
Published: Sep 9, 2026 License: AGPL-3.0 Imports: 14 Imported by: 0

Documentation

Overview

Package script is Atlas's in-process worker for polyglot script tasks (PowerShell, Python, JavaScript — ADR-0047). A script task compiles to a job carrying the language's reserved job type (compiler.PwshJobType / PythonJobType / JsJobType); this worker subscribes to a type via a job.Runner and for each job runs the script off the processor goroutine — after fsync — through an Exec, then writes the script's result back into the instance as the task's result variable.

Keeping the interpreter here, not in an engine behavior, is what lets a general -purpose language run without breaking the engine's invariants: the processor stays allocation-free (I1) and side-effect-free on the recovery path (I4), and the result is frozen into the job completion so replay re-applies it verbatim (I6). It mirrors the DMN worker (ADR-0014): one handler per language serves every deployed process, resolving each job's script from the compiled process. The handler itself is language-agnostic; only the Exec differs per language.

Index

Constants

This section is empty.

Variables

View Source
var (
	PowerShell = Lang{
		Name: "powershell", JobType: compiler.PwshJobTypeIndex, Bin: "pwsh",
		Args: func(b string) []string { return []string{"-NoProfile", "-NonInteractive", "-Command", b} },
		Wrap: powershellBootstrap,
	}
	Python = Lang{
		Name: "python", JobType: compiler.PythonJobTypeIndex, Bin: "python3",
		Args: func(b string) []string { return []string{"-c", b} },
		Wrap: pythonBootstrap,
	}
	JavaScript = Lang{
		Name: "javascript", JobType: compiler.JsJobTypeIndex, Bin: "node",
		Args: func(b string) []string { return []string{"-e", b} },
		Wrap: javascriptBootstrap,
	}
)

The three supported languages. Adding one is a new Lang here plus its reserved job type in the compiler — the worker, engine behavior, and recovery are shared.

Langs is every supported language, in a stable order.

Functions

func Handler

func Handler(store state.Reader, lookup ProcessLookup, exec Exec) job.OutputHandler

Handler builds a job handler that runs a script task in one language. Register it with a job.Runner via HandleWithOutput for that language's reserved job type (e.g. compiler.PwshJobTypeIndex); the runner then pulls activatable script jobs, and for each the handler:

  • resolves the script source and result variable from the compiled process,
  • reads the instance's variables as the script's inputs,
  • runs the script through exec (off the processor goroutine, after fsync), and
  • returns the result as the process variable named by the result variable, which the job completion writes back into the instance so a downstream gateway can route on it.

Returning an error leaves the job pending, exactly as for any worker; the runner completes it only on success.

Types

type CmdExec

type CmdExec struct {
	Lang    Lang          // language spec
	Bin     string        // interpreter override; empty means Lang.Bin
	Timeout time.Duration // per-script wall-clock limit; <= 0 means defaultTimeout
	// MaxOutput bounds what one script may write to stdout, in bytes; <= 0 means
	// defaultMaxOutput. The server sets it from the installation's budgets.
	MaxOutput int64
	// contains filtered or unexported fields
}

CmdExec runs script tasks by shelling out to a real interpreter for its Lang. It is the production Exec; tests use a fake instead so they need no interpreter.

Security posture (ADR-0047): the interpreter runs with -NoProfile / -NonInteractive (or the language equivalent), the instance's variables and the source arrive as environment values (not interpolated), each run is bounded by Timeout (the process is killed at the deadline), and it runs in the worker's trust domain — never with the engine's credentials. The eventual isolation boundary is an external worker in the customer's environment.

func New

func New(l Lang) *CmdExec

New returns a CmdExec for the given language.

func (*CmdExec) Check

func (e *CmdExec) Check() error

Check reports whether the interpreter is resolvable on PATH. The server calls it once at startup so an operator whose host lacks the interpreter sees a clear warning, rather than watching script tasks park silently.

func (*CmdExec) Run

func (e *CmdExec) Run(ctx context.Context, source string, input map[string]any) (any, error)

Run passes the source and the variables to the interpreter's bootstrap via the environment, runs it under a deadline, and decodes its stdout as the result. A non-zero exit or a runner error leaves the job pending; an empty stdout decodes to a null result; overrunning the timeout kills the process and errors.

type Exec

type Exec interface {
	Run(ctx context.Context, source string, input map[string]any) (any, error)
}

Exec runs a script off the hot path and returns its result. It is the seam between the worker and the real interpreter: CmdExec shells out to the language's interpreter, but tests inject a deterministic fake so they need no interpreter installed. input is the instance's variables keyed by name; the returned value is the script's result, a JSON-shaped Go value (nil, bool, json.Number, string, []any, or map[string]any) that becomes the result variable.

type Job added in v0.3.0

type Job struct {
	Source string `json:"source"`
	// Input is the scope chain flattened for the script, nearest scope winning
	// (ADR-0068) — resolved by the engine, which is the only one that can walk it.
	Input map[string]any `json:"input,omitempty"`
	// Result names the process variable the script's output is written to; empty
	// means the task writes nothing back.
	Result string `json:"resultVariable,omitempty"`
}

Job is a script task with everything already looked up: the source to run and the variables it sees. It is what travels with a leased job.

func Resolve added in v0.3.0

func Resolve(store state.Reader, cp *compiler.CompiledProcess, detail *compiler.ScriptJobTaskDetail, elementInstanceKey uint64) (Job, error)

Resolve turns a compiled script task into a Job. Engine work by necessity: the source lives in the compiled process and the variables are reached by walking the element instance's scope chain in the store.

type Lang

type Lang struct {
	Name    string // model/UI name, e.g. "python"
	JobType int32  // reserved job-type index (compiler.*JobTypeIndex)
	Bin     string // default interpreter binary
	Args    func(bootstrap string) []string
	Wrap    string // the bootstrap program
}

Lang describes how to run one scripting language: the reserved job type its worker subscribes to, the default interpreter binary, the interpreter arguments that run a bootstrap program, and that bootstrap. The bootstrap is a fixed program (never the author's source) that reads the source and variables from the environment, exposes the variables, runs the source, and prints the result as JSON on stdout (empty output = null). Each language keeps its own idiomatic result convention (see the bootstraps).

func LangByName

func LangByName(name string) (Lang, bool)

LangByName returns the language spec for a (lower-cased) language name, and whether it is one of the supported languages.

type ProcessLookup

type ProcessLookup func(defKey uint64) *compiler.CompiledProcess

ProcessLookup resolves a process-definition key to its compiled process. The worker uses it to find the script source and result variable a job belongs to, so one handler serves every deployed process.

type Result added in v0.3.0

type Result struct {
	ResultVariable string
	Output         any
}

Result is what running a Job produces.

func Run added in v0.3.0

func Run(ctx context.Context, j Job, exec Exec) (Result, error)

Run executes a resolved job through the caller's own interpreter. The in-process path calls it too, so there is one definition of what running a script task means rather than two that drift — only the machine the interpreter sits on differs.

Jump to

Keyboard shortcuts

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