Targets#
A target names a database the run drives. A config that declares no targets drives the single database given by --url and --driver, exactly as it always has. A config that declares several drives them all concurrently from one process, reporting each separately:
target primary(url: env('PRIMARY_URL'))
target replica(url: env('REPLICA_URL'), driver: 'mysql')| Option | Required | Description |
|---|---|---|
url | Yes | Connection URL. Must resolve to a non-empty string. |
driver | No | Database driver. Falls back to --driver when omitted. |
Values come from the environment#
Both options are expressions, not bare text, so a target can be pointed at a database by its environment. That is what makes a multi-target config portable - the config names the roles, the environment supplies the addresses:
let host = env('DB_HOST')
target primary(url: 'postgres://' + host + ':26257/defaultdb')
target replica(url: 'postgres://' + host + ':26258/defaultdb')Because they are expressions, string literals must be quoted:
# Correct.
target primary(url: 'postgres://localhost:26257/defaultdb')
# Wrong - parsed as an expression referring to an unknown name.
target primary(url: postgres://localhost:26257/defaultdb)Targets resolve before any connection is opened, which is what lets them decide where to connect. env(), globals (let) and arithmetic all work. Anything needing a live database does not, and neither do expr functions, which are compiled later in startup.
urlanddrivermust resolve to strings.env_nil()on an unset variable yieldsnil, so wrap it:coalesce(env_nil('REPLICA_URL'), 'postgres://localhost:26257/defaultdb').
How many targets#
| Targets declared | Behaviour |
|---|---|
| None | One database, from --url / --driver. Metrics are labelled default. |
| One | One database, from the target. Same single-stream run, but metrics and output take the target’s name. |
| Two or more | One connection and one workload stream per target, run concurrently and rendered side by side with a delta table against the first target. |
Which target the other commands use#
up, seed, deseed and down act on a single database: the first declared target, or --url/--driver when the config declares none. Only run drives every target.
Use --target to pick a different one, which is how each target gets its own schema and data:
edg up --config workload.edg --target replica
edg seed --config workload.edg --target replica--target works on run too, where it narrows a multi-target config down to that one database instead of driving them all - useful for reproducing one target’s behaviour on its own. Naming a target the config doesn’t declare is an error listing the ones it does.
edg workload allrunsupandseedagainst one target, then runs the workload against all of them. Prepare each target with--targetfirst if they need their own data.
Limits are per target#
--max-queries and --max-qps apply to each target independently rather than across the run. Targets are separate workload streams, and a shared budget would let a fast target starve a slow one, which would make the comparison between them meaningless.
Targets and includes#
Targets can live in an included file, which is the usual way to share one set of connections across configs:
# targets.edg
target primary(url: env('PRIMARY_URL'))
target replica(url: env('REPLICA_URL'))include 'targets.edg'Included targets are appended after the including file’s own. A name declared in both files is an error, not an overwrite.