Run the load tests on Postgres too, as production runs (#139)

node tests/load/run.js --postgres puts the scratch daemon in IPX_TEST_DATABASE_URL, the database
the Rust tests already use on Postgres, ipodderx_test on the databases project's server, in a
schema of its own, ipx_load, dropped and made again each run as /tmp/ipx-load is wiped. The URL
is in /src/.envrc, taken from ipx.env. It is production's server and role, so the harness refuses
a database whose name does not end in _test, and hands psql the password in its environment,
where no other process on Tower can read it. psql comes from /src/install.sh.

After seeding it runs ANALYZE: a schema filled seconds before has no planner statistics until
autovacuum gets there, which it did partway through a test, and the search's p95 swung between
40ms and 166ms from run to run. Analyzed first, three runs gave 37-38ms.

Each budget now has a value for each database, about twice what it measures on Tower: Postgres
answers the feed list at p95 54ms to SQLite's 242, having no one connection to queue for (#136).
Running it found #140.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-05 18:31:18 +00:00
parent 8c4a5f396b
commit bbdcbe213f
7 changed files with 72 additions and 25 deletions

View File

@@ -1,6 +1,6 @@
import http from 'k6/http';
import { check, sleep } from 'k6';
import { BASE, FEEDS, ITEMS, as, me, pick, feedId } from './lib.js';
import { BASE, FEEDS, ITEMS, as, me, pick, feedId, p95 } from './lib.js';
// An evening's browsing: twenty-five people at once opening their feed list, All Subscriptions,
// a feed, a search, the Directory and a feed's page in it. Each answer's budget is well above what
@@ -17,13 +17,14 @@ export const options = {
thresholds: {
http_req_failed: ['rate==0'],
checks: ['rate==1'],
// About twice each one's p95 on 2026-10-05, SQLite on Tower: 236, 118, 133, 119, 259, 312ms.
'http_req_duration{name:feeds}': ['p(95)<500'],
'http_req_duration{name:all-entries}': ['p(95)<300'],
'http_req_duration{name:feed-entries}': ['p(95)<300'],
'http_req_duration{name:search}': ['p(95)<300'],
'http_req_duration{name:directory}': ['p(95)<600'],
'http_req_duration{name:listed}': ['p(95)<700'],
// About twice each one's p95 on 2026-10-05 on Tower. SQLite: 236, 118, 133, 119, 259, 312ms;
// Postgres: 54, 34, 24, 44, 71, 88ms.
'http_req_duration{name:feeds}': p95(500, 150),
'http_req_duration{name:all-entries}': p95(300, 100),
'http_req_duration{name:feed-entries}': p95(300, 100),
'http_req_duration{name:search}': p95(300, 100),
'http_req_duration{name:directory}': p95(600, 200),
'http_req_duration{name:listed}': p95(700, 200),
},
};