A full-stack load-testing analytics platform that helps teams measure, visualize, and optimize API performance under load.
OpenLoad is a modern load-testing analytics tool designed to:
- Create and manage load tests for HTTP and WebSocket services (gRPC, GraphQL, SOAP architecture in place)
- Prepare reusable datasets for parameterized load tests β collect rows from APIs and inject them as variables
- Schedule automated tests with cron expressions for continuous performance monitoring
- Organize tests by projects and services for better scalability tracking
- Capture detailed metrics from test runs (response times, throughput, error rates)
- Visualize performance trends with percentile-based analytics (p50, p75, p95, p99)
- Track historical data to compare performance across test runs
Note: This project uses Reflex 0.9.0+. See Development Requirements below for compatibility notes on icon naming, component API changes, and port configuration.
cd deployment/
docker compose up -dServices:
- Frontend: http://localhost:8180 (Reflex UI)
- Backend API: http://localhost:8182 (Fiber server)
- Backend Health Check: http://localhost:8182/health
- PostgreSQL: localhost:5432
- ClickHouse: localhost:9001
The frontend auto-migrates the database schema and loads sample data on first run.
Stop services:
docker compose downRebuild after code changes:
docker compose build
docker compose up -dmake build # Compile binary
make run # Run with live reloading
make test # Run all tests
make clean # Clean build artifactsThe Fiber server listens on http://localhost:8182.
pip install -r requirements.txt
reflex init # One-time setup
reflex run # Start dev server (auto-compiles on change)The Reflex dev server listens on http://localhost:8180.
# Start only databases
cd deployment/
docker compose up -d postgres clickhouse
# Then run backend/frontend locally (Option 2)| Component | Version | Notes |
|---|---|---|
| Go | 1.26 | Uses log/slog, slices, cmp, and built-in max/min |
| Python | 3.14 | Uses match/case structural pattern matching |
| Reflex | 0.9.0+ | See compatibility notes below |
This project uses Reflex 0.9.0+. The upgrade introduced breaking changes:
- Icon naming: Icon names use underscores per Lucide convention (e.g.,
message_circle_checknotcheck-circle) - Callout component: Requires named parameters:
rx.callout(text=..., icon=..., color_scheme=...) - Port configuration: In dev mode, frontend and backend must run on different ports β use
--env devin Docker, not--env prod
graph TB
Client["Browser Client"]
Frontend["Reflex Frontend<br/>(Python)"]
Backend["Fiber API Server<br/>(Go)"]
PG["PostgreSQL<br/>(Projects, Services, Datasets)"]
CH["ClickHouse<br/>(Timeseries Analytics)"]
Client -->|HTTP| Frontend
Frontend -->|HTTP API| Backend
Backend -->|SQL| PG
Backend -->|Timeseries| CH
style Client fill:#e1f5ff
style Frontend fill:#fff3e0
style Backend fill:#f3e5f5
style PG fill:#e8f5e9
style CH fill:#e8f5e9
- Framework: Fiber v3 HTTP server
- Database: PostgreSQL for metadata, ClickHouse for analytics
- Architecture: 4-layer clean architecture (domain β application β infrastructure β delivery)
- Protocols: HTTP (fully implemented), WebSocket (fully implemented), gRPC/GraphQL/SOAP (stubs registered)
- Scheduling: Background cron scheduler (
infrastructure/scheduler/) for automated test execution - Location:
openload_back/
- Framework: Reflex 0.9+ (reactive Python β compiled React)
- Location:
openload_front/openload/ - Layers:
core/api/β per-domain HTTP clients returning typed Pydantic modelscore/services/β thin wrappers over API clientscore/protocols/β load-test protocol plugin system (HTTP, WebSocket, gRPC)shared/models/β Pydantic models for all API types (entities, responses)shared/components/β common UI (sidebar, charts, cards, badges)states/β one state class per featurepages/β thin routing layer, one subdirectory per route group
sequenceDiagram
User->>Frontend: Create/Run Test
Frontend->>Backend: HTTP Request
Backend->>PG: Store Project/Service Metadata
Backend->>ClickHouse: Write Analytics Data
Backend->>Frontend: Return Results
Frontend->>User: Display Metrics & Charts
- Organize load tests by projects (e.g., "Mobile API")
- Define services within projects (e.g., "User Auth", "Payment Gateway")
- Editable service identifiers and metadata
- HTTP and WebSocket protocols fully supported; gRPC/GraphQL/SOAP architecture in place
- Collect rows from APIs using configurable routes and extractors (JSONPath or regex)
- Two collection modes:
repeat(N iterations of main routes) orbatch(fetch a JSON array, one row per element) - Pre/post routes: Run setup/teardown HTTP calls around data collection (e.g., auth β collect β logout)
- Preview: Test collection with a single iteration before committing to a full run
- Dataset injection: Select a completed dataset in the load-test wizard; its columns become injectable variables in route templates
- Versioning: Each re-run increments the dataset version; previous runs are auditable
- Scoping: Global or project/service-scoped datasets with owner/team visibility
- SSRF protection: Two-layer defense β pre-flight DNS validation + DialContext re-validation at TCP connect
- Response time percentiles: p50, p75, p95, p99
- Throughput tracking: Requests per second
- Error analysis: Failure rates and error categorization
- Historical comparison: Track performance across test runs
- Line charts for response time trends
- Throughput over time
- Error rate dashboards
- Run-to-run performance comparison
- Create and configure load tests
- Execute tests against multiple services
- View detailed run history
- Link runs to projects and services for better organization
- Automated execution: Schedule load tests with cron expressions
- Continuous monitoring: Run tests automatically on defined schedules
- Execution history: Track all triggered runs and their results
- Active/Inactive control: Enable/disable without deleting configuration
- Edit Scheduled Jobs: Update run configurations without recreating the schedule
- Pre/post scenarios: Setup (extract tokens, login) β Main routes β Cleanup
- Variable extraction: JSONPath and regex-based extraction from response bodies/headers
- Variable injection: Inject extracted variables into path params, query params, headers, and request body
- Per-VU isolation: Each virtual user maintains its own variable scope across iterations
- Template syntax:
{{varname}}placeholders in URLs, headers, and bodies; builtins:{{uuid}},{{timestamp}},{{random_int:1:100}},{{random_string:8}}
- Connection persistence: Single WebSocket connection per VU for the entire test duration
- Message throughput testing: Configurable intervals and read timeouts for round-trip latency measurement
- Response validation: Exact string / regex / JSONPath validation per message
- Variable support: Extract from and inject variables into WebSocket messages
- Mixed scenarios: HTTP pre/post scenarios with WebSocket main routes
- Connection pooling: Reuse connections across routes with the same target URL
- Failure tolerance: Configurable failure percentage threshold (default 5%)
- Warmup support: RPS and Workers mode warmup for both HTTP and WebSocket tests
- Server-side pagination with dynamic filtering (search, status, project, service)
- Smart sorting by date, name, or status
- Side-by-side run comparison: Compare multiple runs to identify performance regressions
- Delta metrics: Percentage changes relative to a baseline (green = improved, red = degraded)
- Baseline selection: Set any run as baseline
- Multi-metric trends: avg, mean, max, min, p50/p75/p95/p99, req/s, error rates aggregated by date
- Cross-page selection: Select runs from analytics, scheduled runs, and service history pages
- Optimized data fetching: Batch API endpoint reduces NΓ2 sequential requests to 1
openload/
βββ deployment/ # Docker Compose, Dockerfiles
β
βββ openload_back/ # Go backend (Fiber + Clean Architecture)
β βββ cmd/main/ # Entry point
β βββ internal/
β β βββ domain/ # Pure business logic (no external deps)
β β β βββ dataset/ # Dataset entity, repo interface, status constants
β β β βββ execution/ # Runner interface, plan, injector
β β β βββ project/ # Project aggregate, errors
β β β βββ scheduled/ # Scheduled run entity
β β βββ application/ # Use cases, DTOs, orchestration
β β β βββ analytics/ # Run creation, progress, error events
β β β βββ dataset/ # Dataset CRUD, execution, extraction, SSRF guard
β β β βββ project/ # Project/service use cases
β β β βββ scheduled/ # Scheduled run use cases
β β βββ infrastructure/
β β β βββ execution/ # Protocol runners (HTTP β
, WebSocket β
, gRPC stub)
β β β βββ persistence/ # PostgreSQL + ClickHouse repositories
β β β βββ scheduler/ # Cron-based background scheduler
β β βββ delivery/http/ # Fiber handlers, router (thin adapter layer)
β βββ Makefile
β
βββ openload_front/ # Python frontend (Reflex)
β βββ openload/
β β βββ core/
β β β βββ api/ # Per-domain HTTP clients (_base, analytics, project, scheduled, prepare_data)
β β β βββ services/ # Service wrappers (analytics, project, scheduled)
β β β βββ protocols/ # Load-test protocol plugins (HTTP, WebSocket, gRPC)
β β βββ shared/
β β β βββ components/ # Common UI (sidebar, charts, cards, badges, text)
β β β βββ models/ # Pydantic models (entities, responses, prepare_data, load_test_config)
β β β βββ utils/ # format_date, parse_query_param, validation helpers
β β β βββ constants/ # Routes, filter values, run statuses
β β βββ states/ # One state class per feature
β β β βββ analytics_state.py
β β β βββ compare_state.py / compare_selection_state.py
β β β βββ dataset_state.py
β β β βββ load_test_state.py
β β β βββ prep_data_state.py / prep_data_wizard_state.py
β β β βββ project_state.py
β β β βββ run_analytics_state.py
β β β βββ scheduled_state.py
β β β βββ sidebar_state.py
β β βββ pages/ # Thin routing layer
β β βββ analytics/ # Run list
β β βββ analytics_run/ # Single run detail + live polling
β β βββ compare/ # Side-by-side comparison
β β βββ create_test/ # Load-test wizard (HTTP, WebSocket, gRPC tabs)
β β βββ prepare_data/ # Dataset list, detail, create wizard, route editor
β β βββ project_detail/ / service_detail/
β β βββ scheduled_runs/ # List, detail, edit
β βββ requirements.txt
β
βββ docs/
| Concept | Purpose |
|---|---|
| Project | Top-level container (e.g., "E-Commerce Platform") |
| Service | API endpoint definition under a project (HTTP URL or gRPC method) |
| Run | A single load test execution with captured metrics |
| Dataset | A reusable collection of rows gathered from APIs, injected as variables during load tests |
| Analytics | Time-series data: response times, throughput, errors |
- β Project and service management
- β Load test creation and execution (HTTP fully implemented)
- β Response time analytics with percentiles (p50, p75, p95, p99)
- β Single-run metrics dashboard and charts
- β Clean architecture refactor (domain β application β infrastructure β delivery)
- β Run-Project-Service Linking
- β Improved Analytics Page with split-panel sidebar filters
- β Server-Side Pagination with dynamic filtering and sorting
- β Scheduled Tests with cron expressions and execution history
- β Edit Scheduled Jobs
- β Batch Run Fetching (87% faster comparative load)
- β Database Performance: indexed queries, connection pooling
- β Comparative Analysis with delta metrics, baseline selection, trend charts
- β Cross-Page Run Selection
- β Test Scenarios & Variable Extraction/Injection (pre/post scenarios, JSONPath/regex)
- β Per-VU Variable Isolation
- β WebSocket Protocol Support (throughput, validation, extraction, warmup)
- β Real-Time Live Statistics (2s polling, auto-redirect, progress snapshots)
- β Prepare Data (Datasets): API-driven row collection, repeat/batch modes, dataset injection into load tests, SSRF protection, preview, versioning
- β
Frontend architecture refactor: states β
states/, typed Pydantic API layer, split per-domain clients - β Runtime version bump: Go 1.26, Python 3.14
- β
Go modernization:
log/slogstructured logging,slicespackage,cmp.Compare, built-inmax/min - β
Python modernization:
match/casepattern matching across state dispatchers - β
Centralized HTTP error handling via
WriteErroracross all handlers
- Export & Reports: PDF/CSV export of complete run results
- Backend: PDF generation with summary, histograms, error logs, timeseries charts
- Frontend: Export buttons on run detail page
- Performance Regression Detection: Automatic detection of degradation vs baseline
- Compare current run against median of last 5 successful runs
- Flags response time, error rate, and throughput per route with % delta
- Essential for scheduled runs continuous monitoring
- Multi-user / Teams with RBAC: Team-based project management
- Backend: User table, JWT auth, granular project permissions
- Frontend: Login page, team selector, project sharing, audit trail
- Note: Breaking API change; requires database migration planning
- Follow clean architecture: Domain β Application β Infrastructure β Delivery
- Keep domain layer free of external dependencies
- Implement repository interfaces in infrastructure layer
- Add protocol runners to
internal/infrastructure/execution/(implementdomain.execution.Runner) - Register new runners in
cmd/main/main.go - Use status constants from domain packages (e.g.,
domdataset.StatusDraft) β never string literals - Use
log/slogfor structured logging βslog.Info/Warn/Error("message", "key", value), neverlog.Printf - Use
slices.Sort/slices.SortFunc/slices.Containsfrom theslicespackage instead of thesortpackage - Use
cmp.Compareinslices.SortFunccomparators β never subtract integers (overflow risk) - Use the built-in
max/minfunctions (Go 1.21+) β no manual helpers needed - Return
WriteError(c, err)from handlers for consistent HTTP error responses β no ad-hocc.Status(...).JSON(...)on error paths - Run
make testbefore committing; ensurego build ./...passes
- Add new state classes to
states/following existing patterns - Add new API methods to the appropriate client in
core/api/; return typed Pydantic models, never raw dicts - Add new protocol UI plugins to
core/protocols/(implementProtocolPluginbase class) - Use
shared/models/for new Pydantic entity and response models - Use
shared/for truly cross-feature components - All imports must be at module level (enforced by Ruff E402)
- Use
match/casefor dispatching on string values β replaceif/elifchains onactive_tab,kind,sort_by, etc. - Use
rx.match()instead of nestedrx.cond()for pattern matching in templates - Follow copy-mutate-reassign for list state mutations (
deepcopyfor nested structures) - Run
reflex compileand./fix-python.bat --checkbefore committing
Python (Frontend):
cd openload_front
./fix-python.bat --check # Windows
./fix-python.sh --check # macOS/LinuxGo (Backend):
cd openload_back
make test # All tests must pass
make build # Must compile without errors