A production-grade, cloud-native platform for load testing any API endpoint with real-time analytics, distributed tracing, and enterprise-level observability.
- 🚀 Local Deployment — Run full stack on Docker Compose
- 🎓 Vercel Demo Setup — Deploy frontend to Vercel, backend locally (perfect for presentations)
- ⚡ Demo Quick Start — 30-minute demo checklist
- ☸️ Kubernetes Deployment — Production-ready K8s manifests
Core Capabilities
- 🎯 Universal API Testing — Load test any HTTP/HTTPS endpoint with k6 engine
- 📊 Real-Time Analytics — Live metrics via Server-Sent Events (SSE)
- 🔄 Side-by-Side Comparison — Compare performance across test runs
- 📥 Multi-Format Export — Download results as JSON or CSV
- 🔐 Enterprise Auth — JWT and API Key authentication with rate limiting
- 🎨 Modern UI — Dark-themed React dashboard with responsive charts
DevOps & Observability
- 📈 Prometheus Metrics — Custom application and system metrics
- 📉 Grafana Dashboards — Pre-configured performance visualizations
- 🔍 Distributed Tracing — End-to-end request tracing with Jaeger
- 🚨 Smart Alerting — AlertManager with 6 production-ready alert rules
- ⚡ Auto-Scaling — HPA for API pods, KEDA for queue-based worker scaling
┌─────────────────────────────────────────────────────────────────┐
│ 🌐 USER BROWSER │
│ React 18 + Vite • SSE Live Updates │
└──────────────────────────────┬──────────────────────────────────┘
│ HTTPS / SSE
▼
┌─────────────────────────────────────────────────────────────────┐
│ 🔧 BACKEND API (Node.js + Express) │
│ ✓ JWT + API Key Auth ✓ 3-Tier Rate Limiting │
│ ✓ Input Validation ✓ Prometheus /metrics │
│ ✓ OpenTelemetry Tracing ✓ SSE Event Broadcasting │
└──────────┬──────────────────────────────────┬───────────────────┘
│ Enqueue Job │ Real-time Notify
▼ │
┌──────────────────────┐ │
│ 📮 REDIS (BullMQ) │ │
│ • Job Queue │ │
│ • Auto Retry │ │
│ • Concurrency: 3 │ │
└──────────┬───────────┘ │
│ Dequeue Job │
▼ │
┌──────────────────────────────────────────────┴───────────────────┐
│ ⚙️ WORKER PROCESS (Node.js) │
│ 1. Consume jobs from Redis (concurrency: 3) │
│ 2. Spawn k6 as child process (execFile) │
│ 3. Parse k6 JSON output → calculate metrics │
│ 4. UPSERT results to PostgreSQL │
│ 5. Broadcast completion via SSE │
└──────────┬───────────────────────────────────────────────────────┘
│ k6 Load Test (N Virtual Users)
▼
┌──────────────────────┐ ┌──────────────────────────────────────┐
│ 🎯 TARGET API │ │ 🗄️ POSTGRESQL 15 │
│ Any HTTP Endpoint │ │ • benchmark_results table │
│ GET/POST/PUT/DELETE │ │ • 4 Optimized Indexes │
│ Custom Headers │ │ • Connection Pool (max: 20) │
└──────────────────────┘ └──────────────────────────────────────┘
📊 OBSERVABILITY STACK
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Prometheus │ │ Grafana │ │ Jaeger │
│ :9090 │ │ :3001 │ │ :16686 │
│ Metrics │ │ Dashboards │ │ Distributed │
│ Scraping │ │ + Alerts │ │ Tracing │
└──────────────┘ └──────────────┘ └──────────────┘
☸️ KUBERNETES DEPLOYMENT
┌─────────────────────────────────────────────────────────────────┐
│ NGINX Ingress → Frontend Service → Frontend Pods │
│ → Backend Service → Backend Pods (HPA) │
│ → Worker Pods (KEDA) │
│ │
│ • KEDA: Queue-based autoscaling (Redis depth) │
│ • HPA: CPU-based autoscaling (70% threshold) │
│ • PDB: Pod Disruption Budgets for high availability │
└─────────────────────────────────────────────────────────────────┘
| Decision | Rationale |
|---|---|
| Separate Worker Process | k6 is CPU-intensive; isolating it prevents blocking the API event loop |
| BullMQ + Redis Queue | Absorbs traffic spikes — 1000 concurrent requests queue instantly, process 3 at a time |
| SSE over WebSockets | Unidirectional updates are simpler, work over HTTP/1.1, easier to scale |
| UPSERT Pattern | Workers can safely retry failed jobs without creating duplicate records |
| Multi-Stage Docker Builds | Reduces image size by 60%, improves security posture |
| Layer | Technology | Purpose |
|---|---|---|
| Frontend | React 18, Vite, Recharts | Modern SPA with real-time charting |
| Backend | Node.js 20, Express | RESTful API with SSE support |
| Queue | BullMQ + Redis | Async job processing with retry logic |
| Load Testing | k6 | Industry-standard load testing engine |
| Database | PostgreSQL 15 | Persistent storage with optimized indexes |
| Containers | Docker | Multi-stage builds for security & size |
| Orchestration | Kubernetes | Production-grade container orchestration |
| Autoscaling | HPA + KEDA | CPU-based & queue-based scaling |
| CI/CD | GitHub Actions | Automated testing, building, and deployment |
| IaC | Terraform | Infrastructure as Code for AWS EKS |
| Monitoring | Prometheus + Grafana | Metrics collection and visualization |
| Tracing | OpenTelemetry + Jaeger | Distributed request tracing |
| Alerting | AlertManager | Intelligent alert routing and grouping |
| Security | Trivy, Network Policies | Vulnerability scanning and network isolation |
- Docker & Docker Compose
- Node.js 20+ (for local development)
- kubectl & Minikube (for Kubernetes deployment)
- Terraform (for infrastructure provisioning)
Get the entire stack running locally with full deployment experience:
# Clone the repository
git clone <your-repo-url>
cd api-benchmarking-saas
# Create .env from example
cp docker-compose.env.example .env
# Edit .env and set your own passwords
# Start all services (from WSL/Git Bash on Windows)
docker compose up -d postgres redis
docker compose up -d backend worker frontend prometheus grafana alertmanager jaeger
# Verify deployment
./scripts/health-check.sh --timeout 120📌 On Windows? Use WSL or Git Bash, not PowerShell, to avoid Bash script line-ending issues.
📋 See DEPLOYMENT.md for detailed step-by-step deployment instructions and redeploy checklist.
Access the services:
| Service | URL | Credentials |
|---|---|---|
| 🎨 Frontend Dashboard | http://localhost:3000 | — |
| 🔧 Backend API | http://localhost:4000 | API Key: demo-key-12345 |
| 📊 Prometheus | http://localhost:9090 | — |
| 📈 Grafana | http://localhost:3001 | admin / ${GRAFANA_PASSWORD} (see .env) |
| 🚨 AlertManager | http://localhost:9093 | — |
| 🔍 Jaeger UI | http://localhost:16686 | — |
Once you have the Docker-based stack working locally, you can deploy to production-grade Kubernetes:
# 1. Prerequisites: kubectl, a running Kubernetes cluster (EKS, GKE, AKS, etc.)
# 2. Deploy to Kubernetes (requires cluster access and image availability)
kubectl apply -f k8s/namespace.yaml
kubectl apply -f k8s/secrets.yaml
kubectl apply -f k8s/configmap.yaml
kubectl apply -f k8s/postgres-deployment.yaml
kubectl apply -f k8s/redis-ha.yaml
kubectl apply -f k8s/worker-deployment.yaml
kubectl apply -f k8s/backend-deployment.yaml
kubectl apply -f k8s/frontend-deployment.yaml
kubectl apply -f k8s/hpa.yaml
kubectl apply -f k8s/keda-scaledobject.yaml
kubectl apply -f k8s/pdb.yaml
kubectl apply -f k8s/ingress.yaml
kubectl apply -f k8s/network-policies.yaml
# 3. Verify deployment
kubectl get pods -n benchmark-saas
kubectl logs -f deployment/backend -n benchmark-saas📌 Start with Docker Compose first to test the stack locally, then scale to Kubernetes when ready for production.
Provision production infrastructure on AWS:
cd terraform
# Initialize Terraform
terraform init
# Review the execution plan
terraform plan
# Apply infrastructure changes
terraform apply
# Get kubeconfig for the new cluster
aws eks update-kubeconfig --name benchmark-cluster --region us-east-1Terraform provisions:
- EKS cluster with managed node groups
- VPC with public/private subnets
- RDS PostgreSQL instance
- ElastiCache Redis cluster
- Application Load Balancer
- Route53 DNS records
- ACM SSL certificates
📌 For other cloud providers (GCP, Azure, etc.), adapt the Terraform configs or use their native deployment tools.
-
Navigate to Dashboard
http://localhost:3000 -
Configure Test Parameters
- API URL: Enter any HTTP/HTTPS endpoint (e.g.,
https://httpbin.org/get) - Preset: Choose load profile
- 🟢 Light: 10 VUs, 30s duration
- 🟡 Medium: 20 VUs, 60s duration
- 🔴 Stress: 50 VUs, 120s duration
- Authentication (optional):
- Bearer Token
- API Key
- Custom JSON headers
- API URL: Enter any HTTP/HTTPS endpoint (e.g.,
-
Execute & Monitor
- Click Run Load Test
- Watch real-time metrics update via SSE
- View response time, throughput, error rate
-
Analyze Results
- Export as JSON or CSV
- Compare with previous runs
- View detailed metrics in Grafana
Basic Test:
curl -X POST http://localhost:4000/api/benchmark/run \
-H "X-API-Key: demo-key-12345" \
-H "Content-Type: application/json" \
-d '{
"apiUrl": "https://httpbin.org/get",
"vus": 10,
"duration": "10s"
}'Response:
{
"testId": "test_1234567890",
"status": "queued",
"message": "Load test queued successfully"
}Check Test Status:
curl http://localhost:4000/api/benchmark/test_1234567890 \
-H "X-API-Key: demo-key-12345"Test with Authentication Headers:
curl -X POST http://localhost:4000/api/benchmark/run \
-H "X-API-Key: demo-key-12345" \
-H "Content-Type: application/json" \
-d '{
"apiUrl": "https://api.github.com/user",
"vus": 5,
"duration": "10s",
"method": "GET",
"headers": {
"Authorization": "Bearer YOUR_GITHUB_TOKEN",
"Accept": "application/vnd.github.v3+json"
}
}'POST Request with Body:
curl -X POST http://localhost:4000/api/benchmark/run \
-H "X-API-Key: demo-key-12345" \
-H "Content-Type: application/json" \
-d '{
"apiUrl": "https://httpbin.org/post",
"vus": 15,
"duration": "30s",
"method": "POST",
"body": "{\"key\":\"value\"}",
"headers": {
"Content-Type": "application/json"
}
}'For advanced users who want full control:
k6 run \
--env TARGET_URL=https://httpbin.org/get \
--env VUS=10 \
--env DURATION=10s \
backend/k6/load-test.jsCustom k6 script:
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
vus: 10,
duration: '30s',
};
export default function () {
const res = http.get('https://httpbin.org/get');
check(res, { 'status is 200': (r) => r.status === 200 });
sleep(1);
}The platform supports two authentication methods:
Header: X-API-Key
Demo Key: demo-key-12345
curl http://localhost:4000/api/benchmark/history \
-H "X-API-Key: demo-key-12345"Header: Authorization: Bearer <token>
Obtain a JWT token:
curl -X POST http://localhost:4000/auth/login \
-H "Content-Type: application/json" \
-d '{
"username": "demo",
"password": "demo123"
}'Response:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expiresIn": "24h"
}Use the token:
curl http://localhost:4000/api/benchmark/history \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."| Tier | Limit | Scope |
|---|---|---|
| General API | 100 requests / 15 min | Per IP address |
| Load Tests | 5 tests / 1 min | Per API key |
| Authentication | 10 attempts / 5 min | Per IP address |
💡 Note: The frontend automatically attaches the demo API key for quick testing.
api-benchmarking-saas/
│
├── 🔧 backend/ # Node.js + Express API
│ ├── k6/ # k6 load test scripts
│ │ └── load-test.js # Configurable k6 test
│ └── src/
│ ├── middleware/ # Express middleware
│ │ ├── auth.js # JWT + API Key validation
│ │ ├── rateLimiter.js # 3-tier rate limiting
│ │ └── appMetrics.js # Prometheus metrics
│ ├── routes/ # API endpoints
│ │ ├── benchmark.js # Test execution & results
│ │ ├── auth.js # Login & token generation
│ │ ├── events.js # SSE event stream
│ │ └── metrics.js # Prometheus /metrics
│ ├── db.js # PostgreSQL client (pooled)
│ ├── queue.js # BullMQ queue setup
│ ├── worker.js # k6 job processor
│ ├── tracing.js # OpenTelemetry config
│ ├── logger.js # Winston logger
│ └── index.js # Express app entry
│
├── 🎨 frontend/ # React 18 + Vite SPA
│ └── src/
│ ├── components/
│ │ ├── BenchmarkForm.jsx # Test configuration form
│ │ ├── Dashboard.jsx # Real-time metrics display
│ │ ├── ResultsHistory.jsx # Test history table
│ │ ├── CompareView.jsx # Side-by-side comparison
│ │ ├── Toast.jsx # Notification system
│ │ └── ErrorBoundary.jsx # Error handling
│ ├── App.jsx # Main app component
│ └── main.jsx # React entry point
│
├── ☸️ k8s/ # Kubernetes manifests (16 files)
│ ├── namespace.yaml # Isolated namespace
│ ├── secrets.yaml # Sensitive config (base64)
│ ├── configmap.yaml # Non-sensitive config
│ ├── postgres-deployment.yaml # PostgreSQL StatefulSet
│ ├── redis-ha.yaml # Redis with Sentinel
│ ├── backend-deployment.yaml # API pods
│ ├── frontend-deployment.yaml # Frontend pods
│ ├── worker-deployment.yaml # Worker pods
│ ├── hpa.yaml # Horizontal Pod Autoscaler
│ ├── keda-scaledobject.yaml # Queue-based autoscaling
│ ├── pdb.yaml # Pod Disruption Budgets
│ ├── ingress.yaml # NGINX Ingress rules
│ ├── network-policies.yaml # Network isolation
│ ├── cert-manager.yaml # TLS certificate automation
│ ├── jaeger.yaml # Distributed tracing
│ └── secrets-rotation.yaml # Automated secret rotation
│
├── 🏗️ terraform/ # Infrastructure as Code
│ ├── main.tf # AWS EKS cluster
│ ├── vpc.tf # Network configuration
│ ├── rds.tf # PostgreSQL RDS
│ ├── elasticache.tf # Redis cluster
│ ├── variables.tf # Input variables
│ └── outputs.tf # Output values
│
├── 📊 monitoring/ # Observability stack
│ ├── prometheus/
│ │ ├── prometheus.yml # Scrape configs
│ │ └── alerts.yml # 6 alert rules
│ ├── grafana/
│ │ ├── dashboards/
│ │ │ └── benchmark-dashboard.json
│ │ └── provisioning/ # Auto-provisioning
│ └── alertmanager/
│ └── alertmanager.yml # Alert routing
│
├── 🔄 .github/workflows/ # CI/CD pipelines
│ └── ci-cd.yml # Lint, Test, Build, Deploy
│
├── docker-compose.yml # Local development stack
└── README.md # This file
Automated workflows powered by GitHub Actions:
┌──────────────────┐ ┌─────────────────┐ ┌──────────────────┐
│ Validate & Test│ --> │ Build Images │ --> │ Deploy & Verify │
│ │ │ │ │ │
│ • ESLint │ │ • Docker Build │ │ • Docker Compose │
│ • Vitest │ │ • Frontend Build│ │ • Health Checks │
│ • Jest │ │ • Image Tag │ │ • Integration Test│
│ • npm audit │ │ • Push to Hub │ │ • k6 Load Test │
│ • Security Scan │ │ • Artifact Save │ │ • Artifact Upload │
└──────────────────┘ └─────────────────┘ └──────────────────┘
The CI/CD pipeline is defined in .github/workflows/ci-cd.yml.
Pipeline runs on:
- Every push to
main - Every pull request
- Manual trigger via
workflow_dispatch
- ✅ Automated Testing — Unit, integration, and E2E tests
- 🔒 Security Scanning — Trivy for CVE detection (fails on CRITICAL)
- 🐳 Multi-Stage Builds — Optimized Docker images
- 📦 Artifact Caching — Faster builds with layer caching
- 🔄 Auto Rollback — Reverts on deployment failure
- 📊 Deployment Metrics — Success rate, duration tracking
- 🔔 Slack Notifications — Build status alerts
For Docker Hub publishing and advanced deployments, configure these in your repository settings:
| Secret | Description | Optional | Example |
|---|---|---|---|
DOCKERHUB_USERNAME |
Docker Hub username | ✅ Yes | myusername |
DOCKERHUB_TOKEN |
Docker Hub access token | ✅ Yes | dckr_pat_... |
POSTGRES_PASSWORD |
PostgreSQL password | ✅ Yes | secure_password |
JWT_SECRET |
JWT signing secret | ✅ Yes | random_string_256bit |
GRAFANA_PASSWORD |
Grafana admin password | ✅ Yes | secure_password |
API_KEYS |
Backend API keys | ✅ Yes | prod-key-12345 |
📌 Local deployment uses
.envfile. Secrets are only needed if you want to publish Docker images to a registry or deploy to production.
Access: http://localhost:9090
Custom Metrics Exposed:
| Metric | Type | Description |
|---|---|---|
http_requests_total |
Counter | Total HTTP requests by method, route, status |
http_request_duration_ms |
Histogram | Request latency distribution |
benchmark_tests_total |
Counter | Total load tests executed |
benchmark_test_duration_seconds |
Histogram | Test execution time |
queue_jobs_active |
Gauge | Active jobs in Redis queue |
queue_jobs_waiting |
Gauge | Pending jobs in queue |
nodejs_eventloop_lag_seconds |
Gauge | Event loop lag (performance indicator) |
Example PromQL Queries:
# Request rate (requests per second)
rate(http_requests_total[5m])
# 95th percentile response time
histogram_quantile(0.95, rate(http_request_duration_ms_bucket[5m]))
# Error rate percentage
sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m])) * 100
# Queue depth over time
queue_jobs_waiting + queue_jobs_active
Access: http://localhost:3001 (admin / password from .env GRAFANA_PASSWORD)
Pre-configured Dashboard Panels:
-
System Overview
- Request rate, error rate, latency
- Active connections, queue depth
- CPU and memory usage
-
Load Test Metrics
- Tests per hour
- Average test duration
- Success vs failure rate
-
Database Performance
- Query duration
- Connection pool utilization
- Slow query log
-
Infrastructure Health
- Pod status and restarts
- Node resource utilization
- Network I/O
Import Custom Dashboards:
# Dashboard JSON located at:
monitoring/grafana/dashboards/benchmark-dashboard.jsonAccess: http://localhost:16686
Trace Spans Captured:
- HTTP request lifecycle
- Database queries
- Redis operations
- k6 process execution
- External API calls
How to Use:
- Select service:
benchmark-backend - Choose operation:
POST /api/benchmark/run - Click Find Traces
- Analyze span timeline and dependencies
Trace Context Propagation:
- Uses W3C Trace Context standard
- Automatic correlation across services
- Custom tags for test_id, api_url, vus
Access: http://localhost:9093
Configured Alerts:
| Alert | Condition | Severity | Action |
|---|---|---|---|
| HighCPUUsage | CPU > 80% for 5m | Warning | Scale up pods |
| HighMemoryUsage | Memory > 85% for 5m | Warning | Investigate memory leaks |
| HighErrorRate | Error rate > 5% for 2m | Critical | Page on-call engineer |
| HighLatency | P95 latency > 2s for 5m | Warning | Check database performance |
| BackendDown | No metrics for 1m | Critical | Immediate investigation |
| EventLoopLag | Lag > 100ms for 3m | Warning | Check blocking operations |
Alert Routing:
- Critical → PagerDuty + Slack
- Warning → Slack only
- Grouping by
alertnameandseverity - 5-minute grouping window
Structured JSON Logging with Winston:
{
"timestamp": "2026-05-04T10:30:45.123Z",
"level": "info",
"message": "Load test completed",
"testId": "test_1234567890",
"duration": 30,
"vus": 10,
"requestCount": 1500,
"errorRate": 0.02
}Log Levels:
error— Application errors, exceptionswarn— Degraded performance, rate limitsinfo— Test execution, API requestsdebug— Detailed execution flow (dev only)
View Logs:
# Docker Compose
docker compose logs -f backend
# Kubernetes
kubectl logs -f deployment/backend -n benchmark-saas
# Tail last 100 lines
kubectl logs --tail=100 deployment/backend -n benchmark-saas| Feature | Implementation |
|---|---|
| Authentication | JWT (HS256) + API Key |
| Token Expiry | 24 hours (configurable) |
| Password Hashing | bcrypt (10 rounds) |
| API Key Storage | Environment variables |
| CORS | Configured for specific origins |
Implementation: express-rate-limit with Redis store
| Endpoint | Limit | Window |
|---|---|---|
/api/benchmark/run |
5 requests | 1 minute |
/auth/login |
10 requests | 5 minutes |
| All other endpoints | 100 requests | 15 minutes |
Multi-Stage Docker Builds:
# Build stage (large)
FROM node:20-alpine AS builder
# ... build steps ...
# Production stage (minimal)
FROM node:20-alpine
USER node # Non-root user
COPY --from=builder --chown=node:node /app /appSecurity Features:
- ✅ Non-root user execution
- ✅ Minimal base images (Alpine Linux)
- ✅ No unnecessary packages
- ✅ Read-only root filesystem (where possible)
- ✅ Dropped capabilities
Trivy Integration:
# Scan Docker images
trivy image benchmark-backend:latest
# Scan in CI/CD (fails on CRITICAL)
trivy image --severity CRITICAL --exit-code 1 benchmark-backend:latestScan Results:
- Automated scanning on every build
- Blocks deployment if CRITICAL CVEs found
- Weekly scheduled scans for deployed images
Network Policies:
# Default deny all ingress/egress
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- EgressExplicit Allow Rules:
- Backend → PostgreSQL (port 5432)
- Backend → Redis (port 6379)
- Worker → Redis (port 6379)
- Frontend → Backend (port 4000)
- Ingress → Frontend (port 80)
Pod Security Standards:
- Restricted security context
- No privileged containers
- Read-only root filesystem
- Run as non-root user
- Drop all capabilities
Kubernetes Secrets:
# Create secrets from literals
kubectl create secret generic db-credentials \
--from-literal=username=postgres \
--from-literal=password=secure_password \
-n benchmark-saas
# Create from file
kubectl create secret generic jwt-secret \
--from-file=jwt-secret=./jwt.key \
-n benchmark-saasBest Practices:
- ✅ Secrets stored in etcd (encrypted at rest)
- ✅ Mounted as volumes (not environment variables)
- ✅ Automated rotation every 90 days
- ✅ Separate secrets per environment
- ✅ Never committed to Git
cert-manager Integration:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: benchmark-tls
spec:
secretName: benchmark-tls-secret
issuer: letsencrypt-prod
dnsNames:
- benchmark.example.comFeatures:
- Automatic certificate provisioning
- Auto-renewal before expiry
- Let's Encrypt integration
- TLS 1.2+ only
Request Validation:
// URL validation
const urlRegex = /^https?:\/\/.+/;
if (!urlRegex.test(apiUrl)) {
throw new Error('Invalid URL format');
}
// VUs validation
if (vus < 1 || vus > 100) {
throw new Error('VUs must be between 1 and 100');
}
// Duration validation
if (!duration.match(/^\d+[smh]$/)) {
throw new Error('Invalid duration format');
}Sanitization:
- SQL injection prevention (parameterized queries)
- XSS protection (Content Security Policy)
- Command injection prevention (no shell execution)
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
scriptSrc: ["'self'"],
imgSrc: ["'self'", "data:", "https:"],
},
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true,
},
}));Project Configuration:
Copy docker-compose.env.example to .env in the project root:
# PostgreSQL
POSTGRES_PASSWORD=change-this-db-password
# Grafana
GRAFANA_PASSWORD=change-this-grafana-password
# Backend JWT
JWT_SECRET=change-this-jwt-secret
# API Keys
API_KEYS=demo-key-12345
# Optional: Demo credentials
DEMO_ADMIN_PASSWORD=change-this-admin-password
DEMO_USER_PASSWORD=change-this-user-password
# Optional: AI integration
OPENAI_API_KEY=Non-sensitive configuration:
apiVersion: v1
kind: ConfigMap
metadata:
name: backend-config
namespace: benchmark-saas
data:
PORT: "4000"
NODE_ENV: "production"
DB_HOST: "postgres-service"
DB_PORT: "5432"
DB_NAME: "benchmarkdb"
REDIS_HOST: "redis-service"
REDIS_PORT: "6379"
LOG_LEVEL: "info"
WORKER_CONCURRENCY: "3"Sensitive configuration:
# Create secrets
kubectl create secret generic backend-secrets \
--from-literal=DB_PASSWORD='secure_password' \
--from-literal=JWT_SECRET='random_256_bit_string' \
--from-literal=API_KEYS='prod-key-12345' \
-n benchmark-saas
# Verify secrets
kubectl get secrets -n benchmark-saas
kubectl describe secret backend-secrets -n benchmark-saasCustomize in frontend:
// frontend/src/components/BenchmarkForm.jsx
const PRESETS = {
light: { vus: 10, duration: '30s', label: 'Light' },
medium: { vus: 20, duration: '60s', label: 'Medium' },
stress: { vus: 50, duration: '120s', label: 'Stress' },
spike: { vus: 100, duration: '30s', label: 'Spike' },
soak: { vus: 15, duration: '600s', label: 'Soak' },
};PostgreSQL Tuning:
-- Connection pooling
max_connections = 100
shared_buffers = 256MB
effective_cache_size = 1GB
work_mem = 4MB
-- Performance
random_page_cost = 1.1
effective_io_concurrency = 200Indexes:
CREATE INDEX idx_test_id ON benchmark_results(test_id);
CREATE INDEX idx_timestamp ON benchmark_results(created_at DESC);
CREATE INDEX idx_status ON benchmark_results(status);
CREATE INDEX idx_api_url ON benchmark_results(api_url);Issue: Backend fails to connect to PostgreSQL
# Check if PostgreSQL is running
docker compose ps postgres
# View PostgreSQL logs
docker compose logs postgres
# Test connection manually
docker compose exec postgres psql -U postgres -d benchmarkdb -c "SELECT 1;"
# Solution: Ensure DB_HOST matches service name in docker-compose.ymlIssue: Worker not processing jobs
# Check worker logs
docker compose logs worker
# Verify Redis connection
docker compose exec redis redis-cli PING
# Check queue status
docker compose exec redis redis-cli LLEN bull:benchmark:wait
# Solution: Restart worker service
docker compose restart workerIssue: Frontend can't reach backend API
# Check backend health
curl http://localhost:4000/health
# Verify CORS configuration
# backend/src/index.js should include frontend origin
# Solution: Update CORS_ORIGIN environment variableIssue: k6 not found in worker
# Verify k6 installation in Docker image
docker compose exec worker which k6
# Solution: Rebuild worker image
docker compose build workerIssue: High memory usage
# Check container memory
docker stats
# Analyze Node.js heap
docker compose exec backend node --expose-gc --inspect=0.0.0.0:9229 src/index.js
# Solution: Increase container memory limits or optimize queriesPod not starting:
# Check pod status
kubectl get pods -n benchmark-saas
# View pod events
kubectl describe pod <pod-name> -n benchmark-saas
# Check logs
kubectl logs <pod-name> -n benchmark-saas
# Common causes:
# - Image pull errors (check imagePullSecrets)
# - Resource limits too low
# - Missing ConfigMap or SecretService not accessible:
# Check service endpoints
kubectl get endpoints -n benchmark-saas
# Test service internally
kubectl run -it --rm debug --image=alpine --restart=Never -n benchmark-saas -- sh
# Inside pod: wget -O- http://backend-service:4000/health
# Check Ingress
kubectl describe ingress -n benchmark-saasDatabase connection issues:
# Check PostgreSQL pod
kubectl logs -f statefulset/postgres -n benchmark-saas
# Verify secrets
kubectl get secret db-credentials -n benchmark-saas -o yaml
# Test connection from backend pod
kubectl exec -it deployment/backend -n benchmark-saas -- sh
# Inside pod: nc -zv postgres-service 5432Slow API responses:
- Check Prometheus metrics for bottlenecks
- Review Jaeger traces for slow spans
- Analyze database query performance
- Check Redis connection pool
Queue backlog:
# Check queue depth
docker compose exec redis redis-cli LLEN bull:benchmark:wait
# Increase worker concurrency
# Edit backend/.env: WORKER_CONCURRENCY=5
# Scale workers in Kubernetes
kubectl scale deployment worker --replicas=5 -n benchmark-saasConnection Pooling:
// backend/src/db.js
const pool = new Pool({
max: 20, // Maximum connections
min: 2, // Minimum connections
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 2000,
});Redis Optimization:
// backend/src/queue.js
const queue = new Queue('benchmark', {
connection: {
host: process.env.REDIS_HOST,
port: process.env.REDIS_PORT,
maxRetriesPerRequest: 3,
enableReadyCheck: true,
enableOfflineQueue: false,
},
defaultJobOptions: {
attempts: 3,
backoff: {
type: 'exponential',
delay: 2000,
},
removeOnComplete: 100, // Keep last 100 completed jobs
removeOnFail: 50, // Keep last 50 failed jobs
},
});Query Optimization:
-- Use EXPLAIN ANALYZE to identify slow queries
EXPLAIN ANALYZE SELECT * FROM benchmark_results WHERE test_id = 'test_123';
-- Add covering indexes
CREATE INDEX idx_test_results ON benchmark_results(test_id, status, created_at);
-- Vacuum regularly
VACUUM ANALYZE benchmark_results;Connection Pooling:
# k8s/postgres-deployment.yaml
env:
- name: POSTGRES_MAX_CONNECTIONS
value: "200"
- name: POSTGRES_SHARED_BUFFERS
value: "256MB"Horizontal Pod Autoscaler:
# k8s/hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: backend-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: backend
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80KEDA Queue-Based Scaling:
# k8s/keda-scaledobject.yaml
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: worker-scaler
spec:
scaleTargetRef:
name: worker
minReplicaCount: 1
maxReplicaCount: 20
triggers:
- type: redis
metadata:
address: redis-service:6379
listName: bull:benchmark:wait
listLength: "5" # Scale up when queue > 5Gradual Ramp-Up:
// backend/k6/load-test.js
export const options = {
stages: [
{ duration: '2m', target: 10 }, // Ramp up to 10 VUs
{ duration: '5m', target: 10 }, // Stay at 10 VUs
{ duration: '2m', target: 50 }, // Ramp up to 50 VUs
{ duration: '5m', target: 50 }, // Stay at 50 VUs
{ duration: '2m', target: 0 }, // Ramp down
],
};Resource Limits:
# k8s/backend-deployment.yaml
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 2000m
memory: 2GiWe welcome contributions! Please follow these guidelines:
# Fork and clone the repository
git clone https://github.com/your-username/api-benchmarking-saas.git
cd api-benchmarking-saas
# Install dependencies
cd backend && npm install
cd ../frontend && npm install
# Start development environment
docker compose up -d postgres redis
cd backend && npm run dev
cd frontend && npm run dev- JavaScript: ESLint + Prettier
- Commits: Conventional Commits format
- Branches:
feature/,bugfix/,hotfix/prefixes
Example commit:
git commit -m "feat(backend): add support for custom k6 scripts"
git commit -m "fix(frontend): resolve SSE reconnection issue"
git commit -m "docs(readme): update deployment instructions"-
Create a feature branch
git checkout -b feature/your-feature-name
-
Make your changes
- Write clean, documented code
- Add tests for new features
- Update documentation
-
Test your changes
npm run test npm run lint -
Submit PR
- Clear description of changes
- Link related issues
- Include screenshots for UI changes
-
Code Review
- Address reviewer feedback
- Ensure CI/CD passes
- Squash commits if requested
Backend Tests:
cd backend
npm run test # Run all tests
npm run test:unit # Unit tests only
npm run test:integration # Integration tests
npm run test:coverage # Coverage reportFrontend Tests:
cd frontend
npm run test # Run all tests
npm run test:watch # Watch mode
npm run test:coverage # Coverage report- Update README.md for new features
- Add JSDoc comments for functions
- Update API documentation
- Include examples for new endpoints
This project is licensed under the MIT License.
MIT License
Copyright (c) 2026 API Benchmarking SaaS
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
- k6 — Modern load testing tool
- BullMQ — Premium queue package for Node.js
- Prometheus — Monitoring and alerting toolkit
- Grafana — Observability platform
- Jaeger — Distributed tracing system
- Kubernetes — Container orchestration
- Terraform — Infrastructure as Code
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Email: support@example.com
Built with ❤️ for the DevOps community
⭐ Star this repo if you find it useful!