D
DB seeder
Fixtures & lifecycle availableRun seed SQL on start and clean up on stop — a DB fixture.
$ loadr plugin install db-seeder
# Fixtures & lifecycle: a native SERVICE plugin runs setup SQL BEFORE the run and
# teardown SQL AFTER, so every execution starts from the same seeded baseline and
# cleans up after itself — a known state per run instead of accreting rows.
#
# Why a service (not a protocol)? A service has a start/stop lifecycle: loadr
# calls `start(config)` once before any VU and `stop()` once after the last VU
# retires. On start this plugin connects to the database and runs the `setup`
# scripts (create tables, truncate, insert fixtures); on stop it runs `teardown`
# to put the database back. Because seeding happens in start() before the
# executor spins up, the very first request already sees the fixtures; because
# teardown happens in stop(), the database is clean whether the run passed,
# failed a threshold, or was interrupted. Seeding runs ONCE, on the controller —
# not per agent — so a distributed run seeds the shared database a single time.
#
# SQL support is NOT built into loadr core — `db-seeder` is a runtime-loadable
# plugin that ships the heavy `sqlx` Rust driver on its own. It serves both
# `postgres://` and `mysql://` URLs (the driver is chosen from the URL scheme).
#
# Build + install the plugin, then run:
# cargo build -p loadr-plugin-db-seeder --release
# mkdir -p dist && cp plugins/loadr-plugin-db-seeder/plugin.toml dist/ \
# && cp target/release/libloadr_plugin_db_seeder.so dist/
# loadr plugin install dist
# loadr run examples/plugins/db-seeder.yaml
#
# Or point the plan's `plugins:` entry at the built artifact directly (below).
name: db-seeder
description: Seed the database before the run and tear it down after, via the db-seeder service plugin
plugins:
# Resolve `db-seeder` by name from the plugins dir (after
# `loadr plugin install`). To run straight from a build tree instead, set:
# path: target/release/libloadr_plugin_db_seeder.so
# The service starts once before any VU, runs `setup` in order, and runs
# `teardown` in stop() after the run finishes.
- name: db-seeder
config:
# postgres:// or mysql:// URL. Pull it from ${env.DATABASE_URL} so
# credentials stay out of the plan; the URL is redacted from logs.
url: postgres://loadr:loadr@db.example.com:5432/loadr
# Scripts run once, in order, BEFORE any VU begins. Each entry is a path to
# a `.sql` file (relative to `dir`) or an inline SQL string.
setup:
- "TRUNCATE orders, order_items RESTART IDENTITY CASCADE;"
- sql/schema.sql
- sql/seed.sql
# Scripts run once, in order, AFTER the run ends (best-effort: a teardown
# error is logged and counted but does not change the run's exit code).
teardown:
- "TRUNCATE orders, order_items RESTART IDENTITY CASCADE;"
# "abort" (default): a failing setup statement fails start() and the run
# never begins. "continue": log the error and proceed (idempotent scripts).
on_setup_error: abort
# Wrap each script in a single transaction (all-or-nothing). Leave false for
# scripts with statements that cannot run inside a transaction (some DDL).
transaction: false
# Base directory the relative script paths above are resolved against.
dir: .
defaults:
http:
base_url: https://api.example.com
scenarios:
# Because seeding ran in start() before this executor spun up, the very first
# request already sees the fixtures. Teardown runs in stop() once the run ends.
checkout:
executor: constant-vus
vus: 50
duration: 30s
flow:
- request:
name: list
url: /products
checks:
- { type: status, equals: 200 }
- request:
name: checkout
method: POST
url: /checkout
checks:
- { type: status, equals: 200 }
thresholds:
checks: [ "rate>0.99" ]
http_req_failed: [ "rate<0.01" ]
http_req_duration: [ "p(95)<400ms" ]
A real run: install from the signed index, then watch the plugin work.
A runtime plugin, never in the binary
Installing pulls a per-platform driver from the signed index, verifies its SHA-256 and checks its ABI before it ever loads. Remove it any time with loadr plugin remove db-seeder.