Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a15374-f59f-7a31-86d2-d23b5d2ed181
4.7 KiB
Provisional synthetic pilot workload
The owner implementation is scripts/synthetic_pilot.py, configured by
config/synthetic-pilot.json. It reuses the application routes/forms exercised
by existing workflow tests. There was no existing performance driver in this
repository or railiance-apps. The driver uses real loopback HTTP, cookie sessions,
CSRF, Gunicorn and a fresh PostgreSQL 16 container; it never points to an existing
service/database. No live credentials, customer records or publication are needed.
Run from the application repository with its installed locked environment and
cached postgres:16-alpine Docker image:
.venv/bin/python scripts/test_synthetic_pilot.py
.venv/bin/python scripts/synthetic_pilot.py \
--config config/synthetic-pilot.json --output /tmp/vergabe-sizing.json
The container uses a unique name, random loopback database port and disposable
volume; cleanup removes only that container and its volume. Gunicorn binds a
random loopback port. Database, media and issue storage are isolated; temporary
passwords exist only for generated local users. The local settings disable SSO;
this measures local password login, not the invited deployment's identity flow.
No seed_dev command or existing PostgreSQL volume is reused.
Adjustable assumptions
Defaults are two users, two synchronous Gunicorn workers, 100 initial tenders,
180 seconds of ordinary work after 30 seconds idle, and 0.2 seconds think time
per cycle. Each cycle creates a tender, lot and task, and reads list, search and
detail pages; it uploads then downloads one 1 MiB synthetic PDF. Thus the corpus
grows during the run. This is an explicit provisional operation mix, not observed
customer demand. iterations is a per-user safety ceiling; duration normally
ends the run first. User/worker count, duration, idle, iteration ceiling, corpus,
think time, document size, HTTP timeout and ordinary p95 threshold are tunable.
The PDF bytes are a transfer fixture, not a claim of document parser fidelity.
Pass requires all expected operations, ordinary p95 <= 2 seconds and zero failed ordinary/transfer requests. Redirects are not automatically followed: rejected login redirects cannot count as successful data-page responses. Document transfer samples are reported separately. Ordinary samples include the login page/login; fixture creation/migration and readiness are outside the measured workload.
Coverage and interpretation
The result retains individual status/latency/response-size records, phase-tagged 0.5-second Gunicorn process CPU-time/RSS samples, separate interval Docker database stats, driver/config/application source digests, runtime versions, image identity, hardware and UTC boundaries. App RSS sums process resident sets and can double-count shared pages; CPU reflects this host and has no app quota. Database snapshots are separate demand, not allocated to the app by inference. A shared deployment database requires a baseline and attribution before using these observations for capacity.
Startup is readiness-checked, not timed. Idle and fixed-think-time ordinary phases are measured; restart and a distinct burst phase are not. Ingress/TLS/browser/SSO, production quotas, throttling and shared services are unmeasured. Local success does not establish human acceptance or prove the existing 60m production request. Revisit when user count, corpus, document sizes, workers, image, database, hardware or quota changes, and after an owner-approved target-runtime observation window. The existing VERGABE-WP-0019 / RAPPS-WP-0014 human acceptance remains separate.
Provisional allocation calculation
config/synthetic-sizing-margins.json keeps safety factors tunable. After a
complete passing run, derive a candidate envelope without applying it:
.venv/bin/python scripts/summarize_synthetic_sizing.py /tmp/vergabe-sizing.json \
--margins config/synthetic-sizing-margins.json --output /tmp/vergabe-sizing-envelope.json
CPU request is measured aggregate ordinary p95 times 1.5, rounded up to 25m; CPU limit is observed sample peak times 1.5, rounded up to 100m. Memory request is peak summed RSS times 1.25 and limit times 1.5, each rounded up to 64Mi. These are conservative test candidates for this configuration, not measured production requirements. The normalized per-worker CPU value divides aggregate by configured workers; it is not a claim that worker load is equal. No database capacity is folded into the app recommendation. No resource setting is applied by this tool.
The configured cycle creates rather than edits tender/lot/task records. Editing, startup timing, restart, a distinct burst and target-platform quota/throttling remain coverage gaps before full pilot sizing acceptance.