* feat: add load testing framework and initial reports - Introduced k6-based load tests for the Plane API, simulating mixed read/write traffic. - Created comprehensive documentation including a load test report, usage instructions, and configuration details. - Added a load test script to facilitate performance testing with defined thresholds and operation mixes. - Established clear SLO definitions and scaling recommendations based on test results. This addition aims to enhance performance validation and ensure the API can handle expected user loads effectively. * feat: enhance database connection management with environment variables - Added configurable connection management settings for the database, allowing customization of connection max age and health checks via environment variables. - Applied these settings to both the default database and read replica configurations to ensure consistent connection management across the application. This update aims to improve database performance and reliability by enabling better control over connection parameters. * feat: add comprehensive load testing scripts for API performance - Introduced three new load testing scripts using k6: script_100.js, script_500.js, and script_parallel.js, designed to simulate varying levels of user traffic and operations on the Plane API. - Each script includes detailed configurations for request thresholds, timeout settings, and scenarios for both read and write operations. - Removed the outdated script.js to streamline the load testing framework. This enhancement aims to improve performance validation and ensure the API can handle diverse user loads effectively. * refactor: streamline database connection management and enhance load testing scripts - Removed configurable connection management settings from the database configuration in common.py, simplifying the connection setup. - Updated load testing script_parllel.js to separate read and write API endpoints, improving clarity and organization of the load testing framework. - Introduced new constants for read and write project IDs, enhancing the structure of the load testing scripts. This refactor aims to improve maintainability and clarity in both database settings and load testing configurations. * docs: update load test report and usage documentation - Revised the load test report to focus on production infrastructure sizing and deployment guidance, emphasizing measured outcomes and configuration boundaries. - Updated the load testing scripts documentation to clarify the parallel read and write scenarios, including new recommended configurations and usage examples. - Adjusted thresholds in the load testing script to reflect updated performance expectations. These changes aim to enhance clarity and provide better guidance for running load tests in production environments. * docs: update load test report with revised performance metrics - Adjusted load test report to reflect updated performance metrics, including improved response times and success rates for read and write operations. - Revised thresholds and total results to provide a clearer picture of system performance under load. - Enhanced clarity in the report layout for better readability and understanding of results. These updates aim to ensure accurate documentation of load testing outcomes and facilitate better performance analysis.
6.5 KiB
Plane Load Tests
k6-based load tests for the Plane API. The main script runs parallel read and write scenarios: read traffic (GET projects, cycles, modules) and write traffic (create + delete issues) ramp independently.
Prerequisites
- k6 installed
Install k6
# macOS (Homebrew)
brew install k6
# Or download from https://k6.io/docs/get-started/installation/
Quick Start
Recommended: parallel read/write script with JSON output
cd loadtests
k6 run --out json=results_1000.json script_parllel.js
To run without writing results to a file:
k6 run script_parllel.js
Scripts
| Script | Description |
|---|---|
| script_parllel.js | Two scenarios: read (GET projects, cycles, modules) and write (create + delete issues). Read and write VUs ramp independently. Use this for mixed read/write load. |
| script.js | Single-scenario script (all operations in one flow). Simpler, fewer VUs. |
| script_100.js / script_500.js | Variants with different stage targets. |
Configuration (script_parllel.js)
1. Session Cookie
The script authenticates with a single session. Set SESSION_COOKIE in script_parllel.js:
const SESSION_COOKIE =
'session-id=YOUR_SESSION_ID_HERE';
How to get a session cookie:
- Log in to Plane (e.g. https://commercial.loadtest.plane.town)
- Open browser DevTools → Application (or Storage) → Cookies
- Copy the
session-idvalue
2. Write API (workspace plane)
Used only for the write scenario: create issue (POST) and delete issue (DELETE).
const WRITE_API_BASE =
'https://commercial.loadtest.plane.town/api/workspaces/plane/projects';
const WRITE_PROJECT_IDS = [
'uuid-1',
'uuid-2',
'uuid-3',
];
- WRITE_API_BASE – Base URL for the
planeworkspace projects API. - WRITE_PROJECT_IDS – Project UUIDs used for write operations (create/delete issue). The session user must have access to these projects.
3. Read API (workspace loadtest)
Used for all read-scenario requests: GET projects, GET cycles, and GET modules.
const READ_API_BASE =
'https://commercial.loadtest.plane.town/api/workspaces/loadtest';
const READ_PROJECT_IDS = [
'uuid-1',
'uuid-2',
// ... projects used only for GET cycles
];
- READ_API_BASE – Base URL for the
loadtestworkspace (cycles and modules). - READ_PROJECT_IDS – Project UUIDs used for GET cycles. GET modules uses the workspace-level
/modules/endpoint (no project ID).
Ensure the session user has access to both workspaces and the listed projects.
Load Profile (script_parllel.js)
Two scenarios run in parallel.
Read scenario
| Stage | Duration | Target VUs |
|---|---|---|
| Ramp up | 1m | 200 |
| Ramp up | 1m | 400 |
| Ramp up | 1m | 600 |
| Ramp up | 1m | 800 |
| Steady | 5m | 800 |
| Ramp down | 2m | 0 |
Operation mix (per iteration, 3-way rotation):
| Operation | Description |
|---|---|
| GET projects | List projects (READ_API_BASE) |
| GET cycles | List cycles for a project (READ_API_BASE/projects/:id/cycles/) |
| GET modules | List modules (READ_API_BASE/modules/) |
Each read iteration sleeps 2s after the request.
Write scenario
| Stage | Duration | Target VUs |
|---|---|---|
| Ramp up | 1m | 50 |
| Ramp up | 1m | 100 |
| Ramp up | 1m | 150 |
| Ramp up | 1m | 200 |
| Steady | 5m | 200 |
| Ramp down | 2m | 0 |
Operation: Create an issue (POST), then delete it (DELETE). Each write iteration sleeps 3s after.
Thresholds
- http_req_failed: < 5%
- http_req_duration p(95): < 15000 ms (15 s)
A run fails if these thresholds are breached.
Usage Examples
# Run parallel script and write results to JSON (e.g. for 1000 VU equivalent analysis)
k6 run --out json=results_1000.json script_parllel.js
# Run with default options (no JSON output)
k6 run script_parllel.js
# Run simple single-scenario script
k6 run script.js
# Run with custom VUs/duration (overrides script stages)
k6 run --vus 100 --duration 2m script_parllel.js
# Run with verbose output
k6 run --verbose script_parllel.js
Output
k6 prints summary metrics, including:
- http_req_duration – response times (overall and by tag if configured)
- http_req_failed – failure rate
- iterations – completed iterations per scenario
- vus – virtual users
With --out json=results_1000.json you can feed the JSON into other tools for analysis or dashboards.
Customization
- options.scenarios – Adjust stages (duration, target VUs) for read and write in
script_parllel.js. - options.thresholds – Change failure or latency SLOs.
- WRITE_PROJECT_IDS / READ_PROJECT_IDS – Add or remove project UUIDs; ensure the session has access.
- sleep() in readFlow (2s) and writeFlow (3s) – Change think time between iterations.
Infrastructure: Database & RDS Proxy
Load tests target an environment with read replicas and RDS Proxy. Ensure both are configured:
| Variable | Purpose |
|---|---|
| DATABASE_URL | Primary writer connection |
| DATABASE_READ_REPLICA_URL | Read replica for queries |
Recommended Settings for Load Tests
For load tests, use stricter connection limits and shorter timeouts:
| Setting | Recommended |
|---|---|
| IdleClientTimeout | 60 |
| MaxConnectionsPercent | 70 |
| MaxIdleConnectionsPercent | 20 |
| ConnectionBorrowTimeout | 5 |
Example RDS Proxy config:
{
"IdleClientTimeout": 60,
"MaxConnectionsPercent": 70,
"MaxIdleConnectionsPercent": 20,
"ConnectionBorrowTimeout": 5,
"SessionPinningFilters": []
}
Application Pods (Kubernetes)
Scale API pods to handle concurrent traffic. Use a Horizontal Pod Autoscaler (HPA) for automatic scaling.
Validated configuration (500 VUs, pods stable):
- Replicas: 6 pods
- Resources per pod:
resources:
limits:
cpu: "2"
memory: 5000Mi
requests:
cpu: 50m
memory: 50Mi
Scale Summary
| Read VUs (max) | Write VUs (max) | Est. req/s | Pods (2 CPU, 5Gi each) | Primary DB | Read replicas |
|---|---|---|---|---|---|
| 800 | 200 | ~120–200 | 10–12 | db.m6gd.large | 1+ |
| Higher | Higher | Scale up | 50–60 for 5k VUs | db.m6gd.xlarge+ | 2+ |
Adjust stages in script_parllel.js and pod/DB resources as needed for your target load.