D

DB seeder

Fixtures & lifecycle available

Run seed SQL on start and clean up on stop — a DB fixture.

Install
$ loadr plugin install db-seeder
examples/plugins/db-seeder.yaml
# 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.