Jobs#
The jobs command group starts an HTTP server and provides CLI clients for submitting and streaming workloads.
Subcommands#
| Command | Description |
|---|---|
edg jobs serve | Start the HTTP server on port 3000 |
edg jobs submit | Submit 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 health | Check job server health |
Server#
Start the job server:
edg jobs serveToken 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-tokenServe flags#
| Flag | Default | Description |
|---|---|---|
--token | Require 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:
| Method | Path | Description |
|---|---|---|
GET | /healthz | Health check (returns ok) |
POST | /jobs | Submit a workload config |
GET | /jobs | List all jobs and their statuses |
GET | /jobs/{id} | Check job status |
GET | /jobs/{id}/stream | Stream 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 1The response contains the job ID:
{"id":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"}Submit flags#
| Flag | Short | Default | Description |
|---|---|---|---|
--server | -s | http://localhost:3000 | Job server address |
--token | Edg-Jobs-Token for authenticated servers | ||
--duration | -d | 1m | Run duration |
--workers | -w | 1 | Number of concurrent workers |
--sections | Lifecycle sections to run, comma-separated (up, seed, run, deseed, down) | ||
--stream | false | Stream live logs after submitting | |
--env | -e | Set an environment variable for env()/env_nil(), as KEY=VALUE (repeatable) | |
--env-file | Read 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 10mTeardown 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.
--durationmeans 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.9SHAPE_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-0e1f2a3b4c5dThe 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 --allWith 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 \
--streamStream flags#
| Flag | Short | Default | Description |
|---|---|---|---|
--server | -s | http://localhost:3000 | Job server address |
--token | Edg-Jobs-Token for authenticated servers | ||
--all | false | Stream every running job |
Status#
Query job status via CLI or HTTP.
All jobs#
edg jobs status --token my-secret-tokencurl 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-0e1f2a3b4c5dcurl http://localhost:3000/jobs/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5dWhile 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#
| Flag | Short | Default | Description |
|---|---|---|---|
--server | -s | http://localhost:3000 | Job server address |
--token | Edg-Jobs-Token for authenticated servers |
Cancel#
Cancel a running job:
edg jobs cancel a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5dReturns the job with status "cancelled". Returns 409 Conflict if the job is not running.
Cancel flags#
| Flag | Short | Default | Description |
|---|---|---|---|
--server | -s | http://localhost:3000 | Job server address |
--token | Edg-Jobs-Token for authenticated servers |
Health Check#
edg jobs healthcurl http://localhost:3000/healthzokHealth flags#
| Flag | Short | Default | Description |
|---|---|---|---|
--server | -s | http://localhost:3000 | Job 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.