diff --git a/load-tests/nrql-queries.sql b/load-tests/nrql-queries.sql new file mode 100644 index 0000000..c8c99a6 --- /dev/null +++ b/load-tests/nrql-queries.sql @@ -0,0 +1,274 @@ +-- ============================================================ +-- HOALedgerIQ – New Relic NRQL Query Library +-- App name: HOALedgerIQ_App +-- Usage: Run in New Relic Query Builder. Replace time windows as needed. +-- ============================================================ + + +-- ── SECTION 1: OVERVIEW HEALTH ──────────────────────────────────────────── + +-- 1.1 Apdex score over last test window +SELECT apdex(duration, t: 0.5) AS 'Apdex' +FROM Transaction +WHERE appName = 'HOALedgerIQ_App' +SINCE 1 hour ago +TIMESERIES 1 minute + +-- 1.2 Overall throughput (requests per minute) +SELECT rate(count(*), 1 minute) AS 'RPM' +FROM Transaction +WHERE appName = 'HOALedgerIQ_App' +SINCE 1 hour ago +TIMESERIES 1 minute + +-- 1.3 Error rate over time +SELECT percentage(count(*), WHERE error IS true) AS 'Error %' +FROM Transaction +WHERE appName = 'HOALedgerIQ_App' +SINCE 1 hour ago +TIMESERIES 1 minute + + +-- ── SECTION 2: LATENCY BY ENDPOINT ──────────────────────────────────────── + +-- 2.1 p50 / p95 / p99 latency by transaction name +SELECT percentile(duration, 50, 95, 99) AS 'ms' +FROM Transaction +WHERE appName = 'HOALedgerIQ_App' +FACET name +SINCE 1 hour ago +LIMIT 30 + +-- 2.2 Slowest endpoints (p95) during load test window +SELECT percentile(duration, 95) AS 'p95 ms' +FROM Transaction +WHERE appName = 'HOALedgerIQ_App' +FACET name +SINCE 1 hour ago +ORDER BY percentile(duration, 95) DESC +LIMIT 20 + +-- 2.3 Auth endpoint latency breakdown +SELECT percentile(duration, 50, 95, 99) +FROM Transaction +WHERE appName = 'HOALedgerIQ_App' + AND name LIKE '%auth%' +FACET name +SINCE 1 hour ago + +-- 2.4 Report endpoint latency (typically slowest reads) +SELECT percentile(duration, 50, 95, 99) +FROM Transaction +WHERE appName = 'HOALedgerIQ_App' + AND name LIKE '%reports%' +FACET name +SINCE 1 hour ago + +-- 2.5 Write endpoint latency (journal-entries, payments, invoices) +SELECT percentile(duration, 50, 95, 99) +FROM Transaction +WHERE appName = 'HOALedgerIQ_App' + AND (name LIKE '%journal-entries%' OR name LIKE '%payments%' OR name LIKE '%invoices%') +FACET name +SINCE 1 hour ago + +-- 2.6 Latency heatmap over time for dashboard load +SELECT histogram(duration, width: 100, buckets: 20) +FROM Transaction +WHERE appName = 'HOALedgerIQ_App' + AND name LIKE '%reports/dashboard%' +SINCE 1 hour ago + + +-- ── SECTION 3: DATABASE PERFORMANCE ────────────────────────────────────── + +-- 3.1 Slowest database queries (top 20) +SELECT average(duration) AS 'avg ms', count(*) AS 'calls' +FROM DatastoreSegment +WHERE appName = 'HOALedgerIQ_App' +FACET statement +SINCE 1 hour ago +ORDER BY average(duration) DESC +LIMIT 20 + +-- 3.2 Database call count by operation type +SELECT count(*) +FROM DatastoreSegment +WHERE appName = 'HOALedgerIQ_App' +FACET operation +SINCE 1 hour ago + +-- 3.3 N+1 detection – high-call-count queries +SELECT count(*) AS 'call count', average(duration) AS 'avg ms' +FROM DatastoreSegment +WHERE appName = 'HOALedgerIQ_App' +FACET statement +SINCE 1 hour ago +ORDER BY count(*) DESC +LIMIT 20 + +-- 3.4 DB time as % of total transaction time (per endpoint) +SELECT average(databaseDuration) / average(duration) * 100 AS '% DB time' +FROM Transaction +WHERE appName = 'HOALedgerIQ_App' + AND databaseDuration IS NOT NULL +FACET name +SINCE 1 hour ago +ORDER BY average(databaseDuration) / average(duration) DESC +LIMIT 20 + +-- 3.5 Connection pool pressure (slow queries that may indicate pool exhaustion) +SELECT count(*) AS 'slow queries (>500ms)' +FROM DatastoreSegment +WHERE appName = 'HOALedgerIQ_App' + AND duration > 0.5 +FACET statement +SINCE 1 hour ago + +-- 3.6 Multi-tenant schema switch overhead (TenantMiddleware) +SELECT average(duration) AS 'avg ms' +FROM Transaction +WHERE appName = 'HOALedgerIQ_App' + AND name NOT LIKE '%auth/login%' + AND name NOT LIKE '%auth/refresh%' +FACET name +SINCE 1 hour ago +ORDER BY average(duration) DESC +LIMIT 20 + + +-- ── SECTION 4: ERROR ANALYSIS ───────────────────────────────────────────── + +-- 4.1 All errors by class and message +SELECT count(*), latest(errorMessage) +FROM TransactionError +WHERE appName = 'HOALedgerIQ_App' +FACET errorClass, errorMessage +SINCE 1 hour ago +LIMIT 30 + +-- 4.2 Error rate by HTTP status code +SELECT count(*) +FROM Transaction +WHERE appName = 'HOALedgerIQ_App' + AND httpResponseCode >= 400 +FACET httpResponseCode +SINCE 1 hour ago +TIMESERIES 1 minute + +-- 4.3 403 errors (WriteAccessGuard rejections under load) +SELECT count(*) AS '403 Forbidden' +FROM Transaction +WHERE appName = 'HOALedgerIQ_App' + AND httpResponseCode = 403 +FACET name +SINCE 1 hour ago + +-- 4.4 429 errors (rate limiter – Throttler) +SELECT count(*) AS '429 Rate Limited' +FROM Transaction +WHERE appName = 'HOALedgerIQ_App' + AND httpResponseCode = 429 +TIMESERIES 1 minute +SINCE 1 hour ago + +-- 4.5 500 errors by endpoint +SELECT count(*), latest(errorMessage) +FROM Transaction +WHERE appName = 'HOALedgerIQ_App' + AND httpResponseCode = 500 +FACET name, errorMessage +SINCE 1 hour ago + +-- 4.6 JWT / auth failures +SELECT count(*) +FROM TransactionError +WHERE appName = 'HOALedgerIQ_App' + AND (errorMessage LIKE '%jwt%' OR errorMessage LIKE '%token%' OR errorMessage LIKE '%unauthorized%') +FACET errorMessage +SINCE 1 hour ago + + +-- ── SECTION 5: INFRASTRUCTURE (during test window) ─────────────────────── + +-- 5.1 CPU utilization +SELECT average(cpuPercent) AS 'CPU %' +FROM SystemSample +WHERE hostname LIKE '%hoaledgeriq%' +SINCE 1 hour ago +TIMESERIES 1 minute + +-- 5.2 Memory utilization +SELECT average(memoryUsedPercent) AS 'Memory %' +FROM SystemSample +WHERE hostname LIKE '%hoaledgeriq%' +SINCE 1 hour ago +TIMESERIES 1 minute + +-- 5.3 Network I/O +SELECT average(transmitBytesPerSecond) AS 'TX bytes/s', + average(receiveBytesPerSecond) AS 'RX bytes/s' +FROM NetworkSample +WHERE hostname LIKE '%hoaledgeriq%' +SINCE 1 hour ago +TIMESERIES 1 minute + + +-- ── SECTION 6: REDIS / BULLMQ ───────────────────────────────────────────── + +-- 6.1 External call latency (Redis) +SELECT average(duration) AS 'avg ms', count(*) AS 'calls' +FROM ExternalSegment +WHERE appName = 'HOALedgerIQ_App' + AND (name LIKE '%redis%' OR host LIKE '%redis%') +FACET name +SINCE 1 hour ago + +-- 6.2 All external service latency +SELECT average(duration) AS 'avg ms', count(*) AS 'calls' +FROM ExternalSegment +WHERE appName = 'HOALedgerIQ_App' +FACET host +SINCE 1 hour ago +ORDER BY average(duration) DESC + + +-- ── SECTION 7: BASELINE COMPARISON ─────────────────────────────────────── + +-- 7.1 Compare this run vs last run (adjust SINCE/UNTIL for your windows) +SELECT percentile(duration, 95) AS 'p95 this run' +FROM Transaction +WHERE appName = 'HOALedgerIQ_App' +FACET name +SINCE '2025-01-01 10:00:00' UNTIL '2025-01-01 11:00:00' +-- Run again with previous window dates to compare + +-- 7.2 Regression check – endpoints that crossed p95 threshold +SELECT percentile(duration, 95) AS 'p95 ms' +FROM Transaction +WHERE appName = 'HOALedgerIQ_App' + AND percentile(duration, 95) > 800 -- adjust to your staging threshold +FACET name +SINCE 1 hour ago + + +-- ── SECTION 8: TENANT-AWARE ANALYSIS ────────────────────────────────────── + +-- 8.1 Performance by org (if orgId is in custom attributes) +SELECT percentile(duration, 95) AS 'p95 ms', count(*) AS 'requests' +FROM Transaction +WHERE appName = 'HOALedgerIQ_App' +FACET custom.orgId +SINCE 1 hour ago +LIMIT 20 + +-- 8.2 Transactions without orgId (potential TenantMiddleware misses) +SELECT count(*) +FROM Transaction +WHERE appName = 'HOALedgerIQ_App' + AND custom.orgId IS NULL + AND name NOT LIKE '%auth/login%' + AND name NOT LIKE '%auth/register%' + AND name NOT LIKE '%health%' +FACET name +SINCE 1 hour ago diff --git a/load-tests/user-pool.csv b/load-tests/user-pool.csv new file mode 100644 index 0000000..847555a --- /dev/null +++ b/load-tests/user-pool.csv @@ -0,0 +1,15 @@ +email,password,orgId,role +treasurer01@loadtest.hoaledgeriq.com,LoadTest123!,org-001,treasurer +treasurer02@loadtest.hoaledgeriq.com,LoadTest123!,org-002,treasurer +treasurer03@loadtest.hoaledgeriq.com,LoadTest123!,org-003,treasurer +admin01@loadtest.hoaledgeriq.com,LoadTest123!,org-001,admin +admin02@loadtest.hoaledgeriq.com,LoadTest123!,org-002,admin +president01@loadtest.hoaledgeriq.com,LoadTest123!,org-001,president +president02@loadtest.hoaledgeriq.com,LoadTest123!,org-002,president +manager01@loadtest.hoaledgeriq.com,LoadTest123!,org-003,manager +manager02@loadtest.hoaledgeriq.com,LoadTest123!,org-004,manager +viewer01@loadtest.hoaledgeriq.com,LoadTest123!,org-001,viewer +viewer02@loadtest.hoaledgeriq.com,LoadTest123!,org-002,viewer +homeowner01@loadtest.hoaledgeriq.com,LoadTest123!,org-001,homeowner +homeowner02@loadtest.hoaledgeriq.com,LoadTest123!,org-002,homeowner +member01@loadtest.hoaledgeriq.com,LoadTest123!,org-001,member_at_large