Documentation
¶
Overview ¶
Package scriptrec records the host calls a managed script's run makes and the answers they were given, and answers a later execution from that record (#1939).
A run cannot read a clock or a random number, its fire time and run id are pinned, and every effect goes through a host binding. A run is therefore a function of its parameters, its state and the answers its host calls returned, and replaying a recording reproduces it exactly: the script's tests run against one (internal/platform/scripttest), and a save replays a script's recent runs through its new source to show what changed (#1942).
What is recorded is the answer a binding was finally given: a call the host paced or retried is recorded once, with the answer the script saw. A recording is gzipped JSON lines, the header first and one call per line, written as the run goes so it never holds more than its compressed bytes, and capped at MaxBytes: a run whose recording outgrows the cap keeps its history and has no recording, and says so.
Index ¶
- Constants
- Variables
- func DescribeCall(tool string, args map[string]any) string
- func ExportKey(req scriptrun.ExportRequest) string
- func PublishKey(req scriptrun.PublishRequest) string
- func SourceHash(source string) string
- func ToolKey(tool string, args map[string]any) string
- type Answerer
- type Call
- type Header
- type Made
- type Meta
- type MissingError
- type Recorder
- type Recording
- type Replay
- type Store
- type Stored
Constants ¶
const ( KindRun = "run" KindDraft = "draft" )
The kinds of run a recording is of.
const MaxBytes = 8 << 20
MaxBytes is the most one run's recording may hold, compressed.
Variables ¶
var ErrNotFound = errors.New("no such recording")
ErrNotFound is a recording no store holds.
Functions ¶
func DescribeCall ¶
DescribeCall names a tool call the way the script wrote it: a query by its SQL, anything else by its tool and arguments.
func ExportKey ¶
func ExportKey(req scriptrun.ExportRequest) string
ExportKey is what an output write is matched by: its name, where it goes, its format and its key.
func PublishKey ¶
func PublishKey(req scriptrun.PublishRequest) string
PublishKey is what a data-region refresh is matched by: the asset's name.
func SourceHash ¶
SourceHash is the hex digest a recording names the source it ran by.
Types ¶
type Answerer ¶
type Answerer interface {
Answer(tool string, args map[string]any) (out map[string]any, errText string, ok bool)
}
Answerer answers a tool call before the recording is consulted. ok is false when it holds no answer for the call; errText is set when the answer it holds is a failure.
type Call ¶
type Call struct {
// Key is what a replay matches a call by: the tool and its arguments, or
// the output's identity.
Key string `json:"key"`
Tool string `json:"tool,omitempty"`
Args map[string]any `json:"args,omitempty"`
Out map[string]any `json:"out,omitempty"`
// Output is set for a written output: what the writer answered.
Output *scriptrun.ExportResult `json:"output,omitempty"`
// Error is the failure the call answered with instead, if it failed.
Error string `json:"error,omitempty"`
}
Call is one host call and its answer: a tool call, or an output the run wrote.
type Header ¶
type Header struct {
V int `json:"v"`
RunID string `json:"run_id"`
FireTime time.Time `json:"fire_time"`
Params map[string]any `json:"params"`
State map[string]any `json:"state"`
RunURL string `json:"run_url,omitempty"`
// MaxRows is the row cap the run's queries carried, which is part of each
// query's arguments.
MaxRows int `json:"max_rows"`
// Preview is true when the run's outputs were previewed rather than
// written: a draft. A replay of it previews them too.
Preview bool `json:"preview"`
}
Header is what a run started from: everything a replay pins so that the calls it makes are the calls the run made.
type Made ¶
Made is one tool call an execution made against a Replay, with what it was answered. Declared is true when a test's declared answer answered it.
type Meta ¶
type Meta struct {
// RunID is the run's id, or the draft's, and is what a test names.
RunID string `json:"run_id"`
// ScriptID is the script recorded, empty for a draft of a script not yet
// saved until a script naming the recording in a test is saved.
ScriptID string `json:"script_id,omitempty"`
ScriptName string `json:"script_name"`
Kind string `json:"kind"`
// RecordedBy is who the recorded run ran for: the draft's author, or the
// owner of the script a run ran.
RecordedBy string `json:"recorded_by"`
// Version is the version a run executed, zero for a draft.
Version int `json:"version,omitempty"`
SourceSHA256 string `json:"source_sha256"`
Succeeded bool `json:"succeeded"`
// Reason says why there is no recording to replay, when there is none.
Reason string `json:"reason,omitempty"`
Bytes int `json:"bytes"`
// Kept is true while a test in the script's latest version names the
// recording, which keeps it past the run-retention sweep.
Kept bool `json:"kept"`
CreatedAt time.Time `json:"created_at"`
}
Meta describes a stored recording.
func (Meta) Replayable ¶
Replayable reports whether the recording can be replayed.
type MissingError ¶
type MissingError struct {
Call string
// Held is how many answers the recording holds for the call, and so how
// many times it could be made.
Held int
}
MissingError is a call the recording holds no answer for. Its text names the call, which is what the author reads to know what the recording lacks.
func (*MissingError) Error ¶
func (e *MissingError) Error() string
type Recorder ¶
type Recorder struct {
// contains filtered or unexported fields
}
Recorder writes one run's recording as the run makes its calls. Hand OnCall to scriptrun.Options.OnCall and wrap the run's Exporter with Exporter.
func NewRecorder ¶
NewRecorder starts a recording of a run that starts from h.
func (*Recorder) Exporter ¶
Exporter wraps the run's writer so that what it answered is recorded. A nil writer stays nil: the run previews, and there is nothing to record.
func (*Recorder) Finish ¶
Finish ends the recording. data is the gzipped recording, nil with the reason when there is none to keep.
type Replay ¶
type Replay struct {
// contains filtered or unexported fields
}
Replay answers an execution's host calls from a recording, and never reaches an upstream: it is the scriptrun.Caller a test and a regression replay run with. Calls with the same key are answered in the order the run made them.
func (*Replay) CallTool ¶
func (r *Replay) CallTool(_ context.Context, name string, args map[string]any) (map[string]any, error)
CallTool answers one tool call from the recording.
func (*Replay) Exporter ¶
Exporter is the writer an execution replaying the recording uses: nil when the recorded run previewed its outputs, so the replay previews them too, and otherwise one answering each write with what the run's writer answered.
func (*Replay) Lenient ¶
Lenient returns the replay answering a tool call the recording holds no answer for with the next unused answer the same tool gave. A test's replay is never lenient; the check that alters a recording's rows is, because the calls a script makes after reading altered rows carry altered arguments.
func (*Replay) WithAnswers ¶
WithAnswers returns the replay answering a tool call from a before the recording.
type Store ¶
type Store interface {
// Save stores a recording, replacing one recorded under the same run id
// (a run taken over from a worker that died records again).
Save(ctx context.Context, rec Stored) error
// Get returns one recording, or ErrNotFound.
Get(ctx context.Context, runID string) (*Stored, error)
// Recent returns the newest replayable recordings of the script's
// successful runs, newest first.
Recent(ctx context.Context, scriptID string, limit int) ([]Stored, error)
// Keep marks the recordings runIDs names as kept, and every other
// recording of the script as not, and attaches to the script the ones
// among them author recorded as drafts of it before it was saved.
Keep(ctx context.Context, scriptID, author string, runIDs []string) error
// Purge deletes the recordings older than retention that are not kept.
Purge(ctx context.Context, retention time.Duration) (int64, error)
}
Store keeps recordings.