Load Testing & Backup

k6 performance test suites with custom metrics, SLA thresholds, CI/CD pipeline integration, and multi-provider backup/DR strategy with actual recovery commands.

SCRIPE includes enterprise-grade k6 load testing scripts that validate performance SLAs under realistic workloads using custom SCRIPE-specific metrics. Combined with a comprehensive backup and disaster recovery strategy covering SQL Server, Oracle, PostgreSQL, and Redis — including actual recovery commands — the platform ensures both performance confidence and data durability across all deployment environments.

k6 Test Suites

Two pre-built k6 test suites cover the critical user journeys: authentication flows (login, JWT retrieval, protected endpoints, health checks) and CRUD operations (pagination, filtering, spike scenarios). Each suite defines VU ramp stages and custom metrics tracked in Grafana.

Test SuiteFileStagesWhat It Tests
Auth Flowtests/load/auth-flow.js2m ramp → 50 VUs × 5m → 1m ramp-downLogin → JWT retrieval → protected endpoints → health check → concurrent sessions
CRUD Operationstests/load/crud-operations.js2m ramp → 30 VUs × 5m → 1m ramp-downCreate → Read (paginated) → Update → Delete with spike scenarios

SLA Thresholds

MetricThresholdDescriptionSLA Impact
http_req_duration (P95)< 2000ms95% of requests must complete within 2 secondsPipeline FAILS if breached
http_req_duration (P99)< 5000ms99% of requests must complete within 5 secondsPipeline FAILS if breached
http_req_failed< 1%Less than 1% of requests may return errorsPipeline FAILS if breached
http_req_duration (avg)< 500msAverage response time under 500msPipeline FAILS if breached
scripe_login_duration (P95)< 3000ms95% of login requests complete in 3 secondsAuth-specific SLA
scripe_login_fail_rate< 5%Less than 5% of login attempts may failAuth reliability SLA

Auth Flow Test Script

The auth-flow.js test simulates realistic user authentication patterns: login with credentials, access a protected endpoint with the JWT token, and verify the health check endpoint. Custom metrics (scripe_login_duration, scripe_login_fail_rate) track auth-specific SLAs independently from general HTTP metrics.

tests/load/auth-flow.js — Key SectionsJavaScript
import http from 'k6/http';
import { check, sleep, group } from 'k6';
import { Rate, Trend } from 'k6/metrics';

// ── Custom Metrics (visible in k6 output + Grafana) ──
const loginDuration = new Trend('scripe_login_duration', true);
const loginFailRate = new Rate('scripe_login_fail_rate');
const tokenRefreshDuration = new Trend('scripe_token_refresh_duration', true);

// ── Environment Configuration ──
const BASE_URL = __ENV.BASE_URL || 'http://localhost:5035';
const ADMIN_EMAIL = __ENV.ADMIN_EMAIL || 'superadmin@scripe.com';
const ADMIN_PASSWORD = __ENV.ADMIN_PASSWORD || 'Admin@123';

/**
 * Exported constant defining parameters and fields for options configurations.
 */
export const options = {
  stages: [
    { duration: '2m', target: 50 },   // Ramp up to 50 concurrent users
    { duration: '5m', target: 50 },   // Sustain load for 5 minutes
    { duration: '1m', target: 0 },    // Ramp down gracefully
  ],
  thresholds: {
    'http_req_duration': ['p(95)<2000', 'p(99)<5000'],
    'scripe_login_duration': ['p(95)<3000'],
    'scripe_login_fail_rate': ['rate<0.05'],
    'http_req_failed': ['rate<0.01'],
  },
};

// Test Flow: Login → Protected Endpoint → Health Check
/**
 * Exported function in the docs module.
 */
export default function () {
  group('1. Login', () => { /* POST /api/auth/login */ });
  group('2. Access Protected Endpoint', () => { /* GET /api/admins/current */ });
  group('3. Health Check', () => { /* GET /health/ready */ });
  sleep(Math.random() * 2 + 1); // Random 1-3s think time
}

Running Load Tests

Running k6 Load TestsShell
# ═══════════════════════════════════════════════════════════
# INSTALL k6
# ═══════════════════════════════════════════════════════════
# Windows:  winget install k6  (or choco install k6)
# macOS:    brew install k6
# Linux:    sudo apt install k6
# Docker:   docker run --rm -i grafana/k6 run - <script.js

# ═══════════════════════════════════════════════════════════
# DEVELOPMENT (local backend)
# ═══════════════════════════════════════════════════════════
# Start your backend first: dotnet run (or scripe dev backend)
k6 run tests/load/auth-flow.js
k6 run tests/load/crud-operations.js

# ═══════════════════════════════════════════════════════════
# DOCKER COMPOSE (containerized backend)
# ═══════════════════════════════════════════════════════════
k6 run tests/load/auth-flow.js \
  --env BASE_URL=http://host.docker.internal:5035

# ═══════════════════════════════════════════════════════════
# STAGING / PRODUCTION (remote server)
# ═══════════════════════════════════════════════════════════
k6 run tests/load/auth-flow.js \
  --env BASE_URL=https://api.staging.scripe.com \
  --env ADMIN_EMAIL=staging-admin@scripe.com \
  --env ADMIN_PASSWORD=StrongP@ss123

# ═══════════════════════════════════════════════════════════
# CUSTOM PARAMETERS
# ═══════════════════════════════════════════════════════════
# Override VUs and duration for quick smoke tests
k6 run tests/load/auth-flow.js -u 10 --duration 30s

# Heavy load test (100 concurrent users, 10 minutes)
k6 run tests/load/auth-flow.js -u 100 --duration 10m

# Output to JSON for CI/CD analysis
k6 run tests/load/auth-flow.js --out json=results.json

# Output to Prometheus for Grafana dashboards
k6 run tests/load/auth-flow.js \
  --out experimental-prometheus-rw \
  --env K6_PROMETHEUS_RW_SERVER_URL=http://localhost:9090/api/v1/write

CI/CD Integration

k6 integrates into GitHub Actions, GitLab CI, and Azure Pipelines. Tests run against a containerized backend instance with health readiness wait before execution. The pipeline fails automatically if any SLA threshold is breached. Results are uploaded as artifacts for trend analysis.

GitHub Actions — Load Test JobYAML
name: Load Tests
on:
  schedule:
    - cron: '0 3 * * 1'    # Every Monday at 3 AM
  workflow_dispatch:         # Manual trigger

jobs:
  load-test:
    runs-on: ubuntu-latest
    services:
      api:
        image: scripe-api:latest
        ports: ['5035:5035']
        env:
          ASPNETCORE_ENVIRONMENT: Staging
          Database__Provider: SqlServer
          Database__ConnectionString: ${{ secrets.TEST_DB_CONNECTION }}
    steps:
      - uses: actions/checkout@v4

      - name: Wait for API readiness
        run: |
          for i in {1..30}; do
            curl -sf http://localhost:5035/health/ready && break
            sleep 5
          done

      - name: Run Auth Flow Test
        uses: grafana/k6-action@v0.3.1
        with:
          filename: tests/load/auth-flow.js
          flags: >-
            --env BASE_URL=http://localhost:5035
            --env ADMIN_EMAIL=${{ secrets.TEST_ADMIN_EMAIL }}
            --env ADMIN_PASSWORD=${{ secrets.TEST_ADMIN_PASSWORD }}
            --out json=auth-results.json

      - name: Run CRUD Operations Test
        uses: grafana/k6-action@v0.3.1
        with:
          filename: tests/load/crud-operations.js
          flags: >-
            --env BASE_URL=http://localhost:5035
            --env ADMIN_EMAIL=${{ secrets.TEST_ADMIN_EMAIL }}
            --env ADMIN_PASSWORD=${{ secrets.TEST_ADMIN_PASSWORD }}

      - name: Upload Results
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: k6-results
          path: auth-results.json

Backup & Disaster Recovery

SCRIPE supports multi-provider backup strategies with specific tools, frequencies, and recovery commands tailored to each database engine. The backup strategy ensures compliance with enterprise RPO (Recovery Point Objective) and RTO (Recovery Time Objective) requirements. Audit logs have a separate backup with extended retention for compliance.

ComponentStrategyFrequencyRetentionRecovery Tool
SQL ServerFull + Differential + Transaction LogDaily / Hourly / 15min30 daysSSMS Restore or T-SQL RESTORE DATABASE
OracleRMAN Full + Incremental + Archive LogWeekly / Daily / Continuous30 daysRMAN RECOVER + RESTORE
PostgreSQLpg_dump + WAL archivingDaily + Continuous30 dayspg_restore + Point-in-Time Recovery
RedisRDB snapshots + AOF persistenceHourly + Real-time7 daysredis-cli --rdb / AOF replay
File StorageCloud provider snapshots or rsyncDaily90 daysCloud console restore or rsync reverse
Audit LogsSeparate backup (compliance requirement)Daily1 year minimumSQL restore to read-only replica
Backup & Recovery CommandsShell
# ═══════════════════════════════════════════════════════════
# SQL SERVER BACKUP (Windows / Docker)
# ═══════════════════════════════════════════════════════════
# Full backup
sqlcmd -S localhost -U sa -P 'YourPassword' -Q \
  "BACKUP DATABASE SCRIPE TO DISK='/backups/scripe_full.bak'"

# Point-in-time restore
sqlcmd -S localhost -U sa -P 'YourPassword' -Q \
  "RESTORE DATABASE SCRIPE FROM DISK='/backups/scripe_full.bak' \
   WITH STOPAT='2026-04-06T20:00:00'"

# ═══════════════════════════════════════════════════════════
# POSTGRESQL BACKUP (Linux / Docker)
# ═══════════════════════════════════════════════════════════
# Full dump
pg_dump -h localhost -U scripe -d scripe_db -F c > scripe_backup.dump

# Restore
pg_restore -h localhost -U scripe -d scripe_db scripe_backup.dump

# ═══════════════════════════════════════════════════════════
# REDIS BACKUP
# ═══════════════════════════════════════════════════════════
# Trigger RDB snapshot
redis-cli BGSAVE

# Copy RDB file
cp /var/lib/redis/dump.rdb /backups/redis_$(date +%Y%m%d).rdb