openjd

package
v0.2.0 Latest Latest
Warning

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

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

Documentation

Overview

Package openjd implements the OpenJD progress-line interceptor for sqi-worker.

An Interceptor wraps a downstream output handler and inspects each process stdout line for recognized OpenJD directive prefixes:

- openjd_progress: <0-100> — updates the task's in-memory progress percentage - openjd_status: <text> — publishes a live "running" status update via NATS - openjd_fail: <text> — cancels the per-task context and stores a failure reason

All other lines — including unrecognized openjd_* prefixes and all stderr lines — are forwarded to the downstream handler unmodified.

Integration with executor.Executor

Interceptor implements [executor.TaskLifecycleHook], which the executor calls to register per-task metadata (task ID, job ID, session ID, and a context.CancelFunc) before the process starts and to retrieve any stored failure reason after the process exits.

The executor creates a per-task derived context so that openjd_fail cancels only the affected task rather than the worker-wide context.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type EnvOp

type EnvOp struct {
	Kind     EnvOpKind
	Name     string
	Value    string
	Redacted bool
}

EnvOp is a single parsed environment-mutation directive.

  • Kind reports whether the variable is being set or unset.
  • Name is the (validated) environment variable name.
  • Value is the variable value (set only; empty for unset).
  • Redacted is true when the value originated from openjd_redacted_env and therefore must never be written to logs in cleartext.

func ParseEnvDirective

func ParseEnvDirective(line string) (EnvOp, bool)

ParseEnvDirective classifies a single stdout line as one of the three OpenJD environment directives — openjd_env, openjd_redacted_env, openjd_unset_env — and returns the parsed mutation. ok is false when the line is not a valid environment directive (unrecognized prefix, malformed payload, or an invalid environment variable name); callers should log and ignore such lines.

Surrounding whitespace is trimmed. For set directives the payload is split on the FIRST '=' so values may themselves contain '='. For unset the payload is the bare variable name. Names must be non-empty, start with a non-digit, and contain only ASCII letters, digits, and underscores (OpenJD's env-name rule).

type EnvOpKind

type EnvOpKind int

EnvOpKind classifies an EnvOp as either a set (assign/override) or an unset (remove) operation on the session environment.

const (
	// EnvOpSet sets or overrides an environment variable to Value.
	EnvOpSet EnvOpKind = iota
	// EnvOpUnset removes an environment variable.
	EnvOpUnset
)

type Interceptor

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

Interceptor is an output handler that intercepts recognized OpenJD directive lines from process stdout before forwarding the rest to the downstream handler.

Interceptor also implements executor.TaskLifecycleHook so the executor can register per-task metadata (including a cancel function for openjd_fail) and retrieve any stored failure reason after the process exits.

Interceptor is safe for concurrent use from multiple goroutines.

func New

func New(downstream outputHandler, nc natsPublisher, workerID string, logger *slog.Logger) *Interceptor

New returns a ready-to-use Interceptor.

downstream receives all non-directive stdout lines and all stderr lines. nc is used to publish openjd_status messages to the task.status NATS subject. workerID is embedded in every status message published by the interceptor.

func (*Interceptor) Deregister

func (i *Interceptor) Deregister(attemptID string)

Deregister removes the per-task state for attemptID. Safe to call multiple times.

func (*Interceptor) FlushLogs

func (i *Interceptor) FlushLogs(ctx context.Context, taskID, attemptID string) error

FlushLogs forwards a flush request to the downstream handler if it implements the optional FlushLogs method. This allows the executor to call FlushLogs on the Interceptor (which it holds as the configured OutputHandler) and have the call reach the logstreamer that wraps underneath.

A local interface is used instead of importing executor.LogFlusher to avoid a circular dependency between the openjd and executor packages.

func (*Interceptor) HandleLine

func (i *Interceptor) HandleLine(ctx context.Context, taskID, attemptID, sessionID, stream, line string)

HandleLine intercepts recognized OpenJD directive lines from stdout and forwards everything else to the downstream handler unmodified.

Stderr lines are always forwarded without inspection because tasks are expected to emit directives only to stdout. Recognized directive lines (openjd_progress, openjd_status, openjd_fail) are consumed without forwarding; all other lines — including unrecognized openjd_* prefixes — are passed through.

func (*Interceptor) LastProgress

func (i *Interceptor) LastProgress(attemptID string) *int

LastProgress returns the most recent progress percentage (0–100) seen via openjd_progress for the given attemptID, or nil if none has been seen.

This is not part of executor.TaskLifecycleHook; it is provided for callers that include the last-known progress in status messages.

func (*Interceptor) RegisterTask

func (i *Interceptor) RegisterTask(attemptID, taskID, jobID, sessionID string, cancel context.CancelFunc)

RegisterTask associates the given task metadata and cancel function with attemptID. The cancel function is called when an openjd_fail directive is seen, so the executor can terminate the specific task process without canceling the worker context.

RegisterTask must be called before the first HandleLine invocation for the given attemptID.

func (*Interceptor) TakeFailReason

func (i *Interceptor) TakeFailReason(attemptID string) (string, bool)

TakeFailReason returns the failure reason stored by the first openjd_fail directive seen for attemptID, and true if one was present. Returns ("", false) if no openjd_fail was seen.

The stored reason is not cleared by this call; Deregister cleans it up. Repeated calls return a consistent value between RegisterTask and Deregister. An empty reason string with ok=true means openjd_fail was seen with no text.

Jump to

Keyboard shortcuts

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