Jobs#

The jobs command group starts an HTTP server and provides CLI clients for submitting and streaming workloads.

Subcommands#

CommandDescription
edg jobs serveStart the HTTP server on port 3000
edg jobs submitSubmit a workload config to the server
edg jobs status [id]Show status of one or all jobs
edg jobs stream [id...]Stream live progress from one or more running jobs (--all for every running job)
edg jobs cancel <id>Cancel a running job
edg jobs healthCheck job server health

Server#

Start the job server:

edg jobs serve

Token authentication#

Pass --token to require all job endpoints to include a matching Edg-Jobs-Token header (all applicable jobs commands accept the --token flag). The /healthz endpoint is not protected.

edg jobs serve --token my-secret-token

Serve flags#

FlagDefaultDescription
--tokenRequire this token in Edg-Jobs-Token header

The server also hosts a Studio UI at /studio for browser-based job management.

The server exposes six endpoints:

MethodPathDescription
GET/healthzHealth check (returns ok)
POST/jobsSubmit a workload config
GET/jobsList all jobs and their statuses
GET/jobs/{id}Check job status
GET/jobs/{id}/streamStream live progress via SSE
DELETE/jobs/{id}Cancel a running job

Submit#

Submit a workload config from the CLI:

edg jobs submit \
  --url "postgres://root@localhost:26257?sslmode=disable" \
  --driver pgx \
  --config workload.edg \
  --duration 1h \
  --workers 1

The response contains the job ID:

{"id":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"}

Submit flags#

FlagShortDefaultDescription
--server-shttp://localhost:3000Job server address
--tokenEdg-Jobs-Token for authenticated servers
--duration-d1mRun duration
--workers-w1Number of concurrent workers
--sectionsLifecycle sections to run, comma-separated (up, seed, run, deseed, down)
--streamfalseStream live logs after submitting
--env-eSet an environment variable for env()/env_nil(), as KEY=VALUE (repeatable)
--env-fileRead environment variables for env()/env_nil() from a KEY=VALUE file

Separating seed from run#

By default the server runs every lifecycle section the submitted config defines: up, then seed, then the run, with deseed and down after it. --sections narrows that to the phases you name, mirroring the local edg up / edg seed / edg run subcommands:

# Build the schema and seed it. Nothing is torn down afterwards.
edg jobs submit --config workload.edg --url "$URL" --sections up,seed -d 30m

# Drive load against what is already there, as often as you like.
edg jobs submit --config workload.edg --url "$URL" --sections run -d 10m

Teardown obeys the same list, so a run-only job leaves the schema in place for the next one. Omit the flag and nothing changes from previous releases.

Three reasons to reach for it:

  • Sweeps. Pair it with per-job environment and a seeded estate is reused across every iteration, instead of being built and dropped once per run.
  • --duration means what it says. The duration bounds the whole job, so when seeding shares it with the run, a slow seed quietly shortens the measurement. Submitted separately, each pass gets its own budget.
  • Concurrent jobs stay in phase. A config’s sim clock starts when its run phase starts, so jobs submitted together but seeding for different lengths of time end up at different simulated hours. Seeding in a separate pass removes the skew.

Per-job environment#

env('X') and env_nil('X') read the OS environment of whichever process evaluates the config - here, the server, not your shell. --env attaches key/value pairs to the submission so the server resolves them for this job only, falling back to its own OS environment for anything not set:

edg jobs submit --config workload.edg --url "$URL" \
  -e SHAPE_PEAK_HOUR=3 -e SHAPE_AMP=0.9

SHAPE_PEAK_HOUR and SHAPE_AMP mean nothing to edg - workload.edg reads them with env_nil(). See Shapes for a config that does.

--env is repeatable rather than comma-separated, so a value containing a comma survives intact. --env-file is a deliberately dumb KEY=VALUE per line format: # comments and blank lines are skipped, and a value is the rest of the line verbatim - no quote stripping, no escapes, no variable expansion. An explicit --env beats --env-file, and a job’s env beats the server’s OS environment.

Use this for parameters, not secrets. Job env travels in a request header and is held in memory alongside the job.

Job env does not change the server’s process environment. It only affects env()/env_nil() while that job’s config is evaluated, so one job cannot leak its env into the next.

Global flags like --url, --driver, --config, --errors, --retries, --pool-size, --max-conn-lifetime, --max-conn-lifetime-jitter, and --no-atomic-tx are forwarded to the server. See CLI Reference for details.

Stream#

Stream live progress logs from a running job:

edg jobs stream a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d

The connection stays open until the job completes or the stream is cancelled. Progress stats are printed to stdout as they arrive.

Name several jobs, or pass --all to stream every job the server currently reports as running:

edg jobs stream a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d 9f8e7d6c-5b4a-4938-2716-0504f3e2d1c0
edg jobs stream --all

With more than one stream, every line is tagged with the id of the job it came from, and --overwrite is ignored - redrawing stats in place needs sole ownership of the cursor, which no single stream has once they share a terminal. Completed jobs are left out of --all: their logs outlive them, so including them would replay every run the server has done alongside the live ones. A stream that fails doesn’t stop the others; its error is reported once the rest have finished.

Alternatively, pass --stream to submit to stream automatically without needing the job ID:

edg jobs submit \
  --url "postgres://root@localhost:26257?sslmode=disable" \
  --config workload.edg \
  --stream

Stream flags#

FlagShortDefaultDescription
--server-shttp://localhost:3000Job server address
--tokenEdg-Jobs-Token for authenticated servers
--allfalseStream every running job

Status#

Query job status via CLI or HTTP.

All jobs#

edg jobs status --token my-secret-token
curl http://localhost:3000/jobs
[
  {
    "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
    "status": "running",
    "started_at": "2025-04-23T14:32:07Z"
  },
  {
    "id": "f6e5d4c3-b2a1-4f6e-8d7c-9a0b1c2d3e4f",
    "status": "completed",
    "started_at": "2025-04-23T14:30:00Z",
    "completed_at": "2025-04-23T14:30:30Z"
  }
]

Single job#

edg jobs status a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d
curl http://localhost:3000/jobs/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d

While running:

{
  "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
  "status": "running",
  "started_at": "2025-04-23T14:32:07Z"
}

After completion:

{
  "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
  "status": "completed",
  "started_at": "2025-04-23T14:32:07Z",
  "completed_at": "2025-04-23T14:32:37Z"
}

If the workload fails:

{
  "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
  "status": "failed",
  "error": "connecting to database: ...",
  "started_at": "2025-04-23T14:32:07Z",
  "completed_at": "2025-04-23T14:32:07Z"
}

Status flags#

FlagShortDefaultDescription
--server-shttp://localhost:3000Job server address
--tokenEdg-Jobs-Token for authenticated servers

Cancel#

Cancel a running job:

edg jobs cancel a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d

Returns the job with status "cancelled". Returns 409 Conflict if the job is not running.

Cancel flags#

FlagShortDefaultDescription
--server-shttp://localhost:3000Job server address
--tokenEdg-Jobs-Token for authenticated servers

Health Check#

edg jobs health
curl http://localhost:3000/healthz
ok

Health flags#

FlagShortDefaultDescription
--server-shttp://localhost:3000Job server address

Lifecycle#

The server automatically runs up, seed, deseed, and down lifecycle sections if defined in the config. This means a single config file can create tables, seed data, run the workload, and clean up.

Jobs are stored in memory. Restarting the server clears all job history.