GizStack
View .mdOpen in ChatGPTOpen in Claude

gizlang:worker

giz's inference worker protocol, version 1 (giz's ml/worker and wgp-api speak it): a service takes jobs over HTTP on a thread of its own, the caller runs them one at a time where its models are, and the worker keeps each result until giz acknowledges it.

POST /v1/jobs takes {operation, model, input, idempotencyKey} as JSON, or as the form field "request" with the files it names ({"$file": field}), which stream to disk as they arrive; the executor sees each such file as {"$inputFile": {name, contentType, path}}. A key gives the same job for the same request (the first 32 hex digits of SHA-256 of model, operation and key). The worker holds capacity jobs (queued and processing) and answers 429 WORKER_BUSY beyond them. GET, DELETE /v1/jobs/{id} read and cancel a job, POST /v1/jobs/{id}/ack frees a finished one, GET /files/{id}/{name} serves its outputs. GET /v1/queue, /v1/health, /v1/models and /metrics describe the worker; POST /v1/intake/close and /v1/intake/open stop and start new jobs. Each job lives in its own folder under the state folder (job.json, its inputs and outputs), so a restart keeps the queued and finished ones; a job that was processing fails with WORKER_INTERRUPTED. Under serve, where GIZ_WORKER_AUTHORIZATION is set, every /v1/ request must carry it as its Authorization header (401 otherwise).

gizlang
import * as Worker from "gizlang:worker";

Types

Model

gizlang
type Model = { id: string; operation: string; }

A model the worker serves, with its operation ("video.generate").

  • id: string
  • operation: string

Config

gizlang
type Config = { models: Vec<Model>; capacity: i64; state: string; }

The worker: its models, the jobs it holds at once, and the folder of its jobs.

  • models: Vec<gizlang_worker.Model>
  • capacity: i64
  • state: string

Work

gizlang
type Work = { id: string; operation: string; model: string; input: JsonValue; dir: string; }

A job for the executor: its input (files as {"$inputFile": ...}) and the folder its outputs go into.

  • id: string
  • operation: string
  • model: string
  • input: gizlang_json.Json
  • dir: string

Failure

gizlang
type Failure = { code: string; message: string; status: i64; }

Why a job failed: its code (WORKER_INVALID_INPUT, or the executor's own), message and HTTP status (4xx: the request; 5xx: the worker).

  • code: string
  • message: string
  • status: i64

Progress

gizlang
type Progress = { stage: string; step: i64; total: i64; remaining: f64; }

Where a job is: its stage as giz names them (initializing, loading_model, encoding_prompt, generating, encoding_video), its step of total, and the seconds it expects to take still.

  • stage: string
  • step: i64
  • total: i64
  • remaining: f64

Record

gizlang
type Record = { id: string; operation: string; model: string; input: string; status: string; stage: string; step: i64; total: i64; remaining: f64; output: Vec<string>; error: string; code: string; errorStatus: i64; created: i64; started: i64; completed: i64; acknowledged: bool; cancel: bool; }

One job's state. Times are milliseconds since 1970 (0: not yet).

  • id: string
  • operation: string
  • model: string
  • input: string
  • status: string
  • stage: string
  • step: i64
  • total: i64
  • remaining: f64
  • output: Vec<string>
  • error: string
  • code: string
  • errorStatus: i64
  • created: i64
  • started: i64
  • completed: i64
  • acknowledged: bool
  • cancel: bool

State

gizlang
type State = { sys: System; config: Config; jobs: Task.Cell<Vec<Record>>; lock: Task.Atomic; accepting: Task.Atomic; wake: Task.Channel<i64>; done: Task.Atomic; failed: Task.Atomic; aborted: Task.Atomic; busyMs: Task.Atomic; port: Task.Atomic; closing: Task.Atomic; authorization: string; }

What the server's thread and the executor share: the jobs (changed only under lock), whether intake is open, the wake-up of the executor, the counts of finished jobs and their milliseconds, the port the server took (0 until it listens, -1 when it cannot) and whether it is to stop.

  • sys: gizlang_system.System
  • config: gizlang_worker.Config
  • jobs: gizlang_task.Cell<Vec<gizlang_worker.Record>>
  • lock: gizlang_task.Atomic
  • accepting: gizlang_task.Atomic
  • wake: gizlang_task.Channel<i64>
  • done: gizlang_task.Atomic
  • failed: gizlang_task.Atomic
  • aborted: gizlang_task.Atomic
  • busyMs: gizlang_task.Atomic
  • port: gizlang_task.Atomic
  • closing: gizlang_task.Atomic
  • authorization: string

Worker

gizlang
type Worker = { state: State; server: Task.Thread<i64>; port: i64; }

A started worker: its state, the server's thread and its port.

  • state: gizlang_worker.State
  • server: gizlang_task.Thread<i64>
  • port: i64

Functions

start

gizlang
function start(sys: System, host: string, port: i64, config: Config, authorization: string = ""): Worker throws string

Serves config's models on host:port (0: a free port, Worker.port) on an OS thread of its own, so it answers while a job runs. The caller runs the jobs that next gives, on its own thread with the models it keeps loaded, tells their progress to report and their end to finish, and ends with stop. Each /v1/ request must carry authorization as its Authorization header unless it is "".

Effects: fail, read, write, console, io.

next

gizlang
function next(w: Worker): Option<Work>

The next job to run, now processing; it waits for one. None once the worker stops.

Effects: fail, read, write, console, io.

report

gizlang
function report(w: Worker, work: Work, p: Progress): bool

Keeps the progress of work; false once giz cancelled it, when the caller stops it and finishes it with any failure.

Effects: fail, io.

finish

gizlang
function finish(w: Worker, work: Work, result: Result<Vec<string>, Failure>): void

Keeps how work ended: the names of the output files it made in work.dir, or its failure.

Effects: fail, read, write, console, io.

stop

gizlang
function stop(w: Worker): void

Stops the server (requests in flight finish) and waits for its thread; next then gives none.

Effects: fail, io.

invalid

gizlang
function invalid(message: string): Failure

A failure of the job's own input: WORKER_INVALID_INPUT, status 400.

failed

gizlang
function failed(code: string, message: string): Failure

A failure of the worker: code (the executor's own: WORKER_FAILED, WORKER_STORAGE, ...), status 500.

progress

gizlang
function progress(w: Worker, work: Work, stage: string, step: i64, total: i64): bool

Tells giz where work is: its stage, step of total. False once giz cancelled it, when the caller stops it and finishes it with failed(WORKER_CANCELLED, ...).

Effects: fail, io.

uploadedImages

gizlang
function uploadedImages(sys: System, input: JsonValue, key: string): Vec<Img.Image> throws Failure

The pictures of field key of a job's input (one uploaded image, or a list of them), decoded to PICTURE_SIDE.

Effects: fail, io.

seed

gizlang
function seed(sys: System, input: JsonValue, bound: i64 = 4294967296): i64

The seed of a job: its input's seed when 0 or more, else one from the clock below bound.

Effects: fail, io.

serve

gizlang
function serve(sys: System, name: string, host: string, port: i64, config: Config, run: (w: Worker, work: Work) => Result<Vec<string>, Failure>, after: () => void): i64 throws string

Serves config's models on host:port, as start, and runs each job that giz sends, one at a time, with run (the executor: it tells its progress with progress and gives the names of its outputs in work.dir, or fails), then calls after (the models' tunings to save, say). Each job's end and time is printed (the service's journal). It returns when the worker stops.

Effects: fail, read, write, console, io.

inputPath

gizlang
function inputPath(value: JsonValue): Option<string>

The path of an input file ({"$inputFile": {...}}) of a job's input; none for any other value.

Effects: fail.

Constants

WORKER_BUSY

gizlang
const WORKER_BUSY = "WORKER_BUSY"

The error code of a job refused because the worker holds capacity jobs.

WORKER_INTERRUPTED

gizlang
const WORKER_INTERRUPTED = "WORKER_INTERRUPTED"

The error code of a job that was processing when the worker stopped.

WORKER_INVALID_INPUT

gizlang
const WORKER_INVALID_INPUT = "WORKER_INVALID_INPUT"

The error code of a job whose input the executor refuses.

PICTURE_SIDE

gizlang
const PICTURE_SIDE = 2048

The longer side that a picture of a job is decoded to at least: a JPEG or PNG at the smallest scale (1/2, 1/4, 1/8) that keeps it, so a phone photo or a screenshot of any size is within the decoder's bounds. A model reads a picture at 4 megapixels at most, which 2048 covers.