|
| 1 | +## Overview |
| 2 | + |
| 3 | +This app runs repeatable load tests against multiple connectors (Bun+Postgres, CockroachDB, SQLite, Supabase, Convex, SpacetimeDB, etc.). |
| 4 | + |
| 5 | +Each run: |
| 6 | + |
| 7 | +- Loads a scenario from `src/tests/<test-name>/` |
| 8 | +- Runs it against one or more connectors |
| 9 | +- Writes a JSON report into `./runs/` with TPS and latency stats |
| 10 | + |
| 11 | +--- |
| 12 | + |
| 13 | +## Demo Mode |
| 14 | + |
| 15 | +Run a quick performance comparison: |
| 16 | + |
| 17 | +```bash |
| 18 | +npm run demo |
| 19 | +``` |
| 20 | + |
| 21 | +The script will: |
| 22 | + |
| 23 | +- Check that required services are running (prompts you to start them if not) |
| 24 | +- Seed databases with test data |
| 25 | +- Run benchmarks at high contention |
| 26 | +- Display animated results comparing your chosen systems (SpacetimeDB and Convex by default, as both are simple to run locally) |
| 27 | + |
| 28 | +**Options:** |
| 29 | + |
| 30 | +- `--seconds N` - Benchmark duration (default: 10) |
| 31 | +- `--concurrency N` - Concurrent connections (default: 50) |
| 32 | +- `--alpha N` - Contention level (default: 1.5) |
| 33 | +- `--systems a,b,c` - Systems to compare (default: convex,spacetimedb) |
| 34 | +- `--skip-prep` - Skip database seeding |
| 35 | +- `--no-animation` - Disable animated output |
| 36 | + |
| 37 | +--- |
| 38 | + |
| 39 | +## Prerequisites |
| 40 | + |
| 41 | +- **Node.js** ≥ 20.x |
| 42 | +- **pnpm** installed globally |
| 43 | +- **Docker** for local Postgres / Cockroach / Supabase |
| 44 | +- Local/Cloud Convex |
| 45 | + |
| 46 | +From a fresh clone: |
| 47 | + |
| 48 | +```bash |
| 49 | +pnpm install |
| 50 | +``` |
| 51 | + |
| 52 | +--- |
| 53 | + |
| 54 | +## Configuration (`.env`) |
| 55 | + |
| 56 | +Copy `.env.example` to `.env` and adjust. |
| 57 | + |
| 58 | +**Seeding / verification:** |
| 59 | + |
| 60 | +- `SEED_ACCOUNTS` – number of accounts to seed (if unset, code defaults to `100_000`) |
| 61 | +- `SEED_INITIAL_BALANCE` – starting balance per account |
| 62 | +- `VERIFY` – enable extra verification passes when non-zero |
| 63 | +- `ENABLE_RPC_SERVERS` – flag used by scripts that start the RPC benchmark servers |
| 64 | + |
| 65 | +**Runtime toggles:** |
| 66 | + |
| 67 | +- `USE_DOCKER` – `1` = run Docker Compose for Postgres / CockroachDB; `0` = skip |
| 68 | +- `SKIP_PG` – `1` = don't init Postgres in prep |
| 69 | +- `SKIP_CRDB` – `1` = don't init CockroachDB in prep |
| 70 | +- `SKIP_SQLITE` – `1` = don't init SQLite in prep |
| 71 | +- `SKIP_SUPABASE` – `1` = don't init Supabase in prep |
| 72 | +- `SKIP_CONVEX` – `1` = don't init Convex in prep |
| 73 | +- `USE_SPACETIME_METRICS_ENDPOINT` – `1` = read committed transfer counts from the SpacetimeDB metrics endpoint; otherwise only local counters are used |
| 74 | + |
| 75 | +**PostgreSQL / CockroachDB:** |
| 76 | + |
| 77 | +- `PG_URL` – Postgres connection string |
| 78 | +- `CRDB_URL` – CockroachDB connection string |
| 79 | + |
| 80 | +**SQLite:** |
| 81 | + |
| 82 | +- `SQLITE_FILE` – path to the SQLite file |
| 83 | +- `SQLITE_MODE` – tuning preset for the SQLite connector |
| 84 | + |
| 85 | +**SpacetimeDB:** |
| 86 | + |
| 87 | +- `STDB_URL` – WebSocket URL for SpacetimeDB |
| 88 | +- `STDB_MODULE` – module name to load (e.g. `test-1`) |
| 89 | +- `STDB_MODULE_PATH` – filesystem path to the module source (for local dev) |
| 90 | +- `STDB_METRICS_URL` – HTTP URL for the SpacetimeDB metrics endpoint |
| 91 | + |
| 92 | +**Supabase:** |
| 93 | + |
| 94 | +- `SUPABASE_URL` – Supabase project URL |
| 95 | +- `SUPABASE_ANON_KEY` – Supabase anon/public key |
| 96 | +- `SUPABASE_DB_URL` – Postgres connection string for the Supabase database |
| 97 | + |
| 98 | +**Convex:** |
| 99 | + |
| 100 | +- `CONVEX_URL` – Convex deployment URL |
| 101 | +- `CONVEX_SITE_URL` – Convex site URL |
| 102 | +- `CLEAR_CONVEX_ON_PREP` – Convex prep flag (clears data when enabled) |
| 103 | +- `CONVEX_USE_SHARDED_COUNTER` – flag for using the sharded-counter implementation |
| 104 | + |
| 105 | +**Bun / RPC helpers:** |
| 106 | + |
| 107 | +- `BUN_URL` – Bun HTTP benchmark server URL |
| 108 | +- `BUN_PG_URL` – Postgres connection string for the Bun benchmark service |
| 109 | + |
| 110 | +**RPC benchmark servers:** |
| 111 | + |
| 112 | +- `PG_RPC_URL` – HTTP URL for the Postgres RPC server |
| 113 | +- `CRDB_RPC_URL` – HTTP URL for the CockroachDB RPC server |
| 114 | +- `SQLITE_RPC_URL` – HTTP URL for the SQLite RPC server |
| 115 | + |
| 116 | +--- |
| 117 | + |
| 118 | +## Setup |
| 119 | + |
| 120 | +### Generate bindings (first time after clone) |
| 121 | + |
| 122 | +**SpacetimeDB module bindings:** |
| 123 | + |
| 124 | +```bash |
| 125 | +cd spacetimedb |
| 126 | +spacetimedb generate --lang typescript --out-dir ../module_bindings |
| 127 | +cd .. |
| 128 | +``` |
| 129 | + |
| 130 | +**Convex generated files:** |
| 131 | + |
| 132 | +```bash |
| 133 | +cd convex-app |
| 134 | +npx convex dev |
| 135 | +# Wait for it to generate files, then Ctrl+C |
| 136 | +cd .. |
| 137 | +``` |
| 138 | + |
| 139 | +### Start services |
| 140 | + |
| 141 | +1. Start SpacetimeDB (`spacetimedb start`) |
| 142 | +2. Start Convex (inside convex-app run `npx convex dev`) |
| 143 | +3. Init Supabase (run `supabase init`) inside project root. |
| 144 | +4. `npm run prep` to seed the databases. |
| 145 | +5. `npm run bench` to run the test against all connectors. |
| 146 | + |
| 147 | +## Commands & Examples |
| 148 | + |
| 149 | +### 1. Run a test |
| 150 | + |
| 151 | +```bash |
| 152 | +npm run bench [test-name] [--seconds N] [--concurrency N] [--alpha A] [--connectors list] |
| 153 | +``` |
| 154 | + |
| 155 | +Examples: |
| 156 | + |
| 157 | +```bash |
| 158 | +# Default test (test-1), default args (note: only 1 test right now, and it's embedded) |
| 159 | +npm run bench |
| 160 | + |
| 161 | +# Explicit test name |
| 162 | +npm run bench test-1 |
| 163 | + |
| 164 | +# Short run, 100 concurrent workers |
| 165 | +npm run bench test-1 --seconds 10 --concurrency 100 |
| 166 | + |
| 167 | +# Heavier skew on hot accounts |
| 168 | +npm run bench test-1 --alpha 2.0 |
| 169 | + |
| 170 | +# Only run selected connectors |
| 171 | +npm run bench test-1 --connectors spacetimedb,sqlite |
| 172 | +``` |
| 173 | + |
| 174 | +--- |
| 175 | + |
| 176 | +## CLI Arguments |
| 177 | + |
| 178 | +From `src/cli.ts`: |
| 179 | + |
| 180 | +- **`test-name`** (positional) |
| 181 | + - Name of the test folder under `src/tests/` |
| 182 | + - Default: `test-1` |
| 183 | + |
| 184 | +- **`--seconds N`** |
| 185 | + - Duration of the benchmark in seconds |
| 186 | + - Default: `1` |
| 187 | + |
| 188 | +- **`--concurrency N`** |
| 189 | + - Number of workers / in-flight operations |
| 190 | + - Default: `10` |
| 191 | + |
| 192 | +- **`--alpha A`** |
| 193 | + - Zipf α parameter for account selection (hot vs cold distribution) |
| 194 | + - Default: `0.5` |
| 195 | + |
| 196 | +- **`--connectors list`** |
| 197 | + - Optional, comma-separated list of connector `system` names |
| 198 | + - Example: |
| 199 | + |
| 200 | + ```bash |
| 201 | + --connectors spacetimedb,sqlite,postgres |
| 202 | + ``` |
| 203 | + |
| 204 | + - If omitted, all connectors for that test are run |
| 205 | + - The valid names come from `tc.system` in the test modules and the keys in `CONNECTORS` |
| 206 | + |
| 207 | +- **`--contention-tests startAlpha endAlpha step concurrency`** |
| 208 | + - Runs a sweep over Zipf α values for a single connector |
| 209 | + - Uses `startAlpha`, `endAlpha`, and `step` to choose the α values |
| 210 | + - Uses the provided `concurrency` for all runs |
| 211 | + |
| 212 | +- **`--concurrency-tests startConc endConc step alpha`** |
| 213 | + - Runs a sweep over concurrency levels for a single connector |
| 214 | + - Uses `startConc`, `endConc`, and `step` to choose the concurrency values |
| 215 | + - Uses the provided `alpha` for all runs |
| 216 | + |
| 217 | +--- |
| 218 | + |
| 219 | +### Running in Docker |
| 220 | + |
| 221 | +You can also run the benchmark via Docker instead of Node directly: |
| 222 | + |
| 223 | +```bash |
| 224 | +docker compose run --rm bench \ |
| 225 | + --seconds 5 \ |
| 226 | + --concurrency 50 \ |
| 227 | + --alpha 1 \ |
| 228 | + --connectors convex |
| 229 | +``` |
| 230 | + |
| 231 | +If using Docker, make sure to set `USE_DOCKER=1` in `.env`, verify docker-compose env variables, verify you've run supabase init, and run `npm prep` before running bench. |
| 232 | +
|
| 233 | +## Output |
| 234 | +
|
| 235 | +Every run writes a JSON file into `./runs/`: |
| 236 | +
|
| 237 | +- Directory: `./runs/` |
| 238 | +- Filename: `<test-name>-<timestamp>.json` |
| 239 | + - Example: `test-1-2025-11-17T16-45-12-345Z.json` |
| 240 | +
|
| 241 | +Point your visualizations / CSV exports at `./runs/` and you’re good. |
0 commit comments