File size: 12,765 Bytes
aef804e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
# Load Testing with Locust

This directory contains Locust load tests for validating Atom API performance under concurrent user load.

## Overview

Load testing simulates multiple concurrent users interacting with the API to identify performance bottlenecks, establish capacity limits, and validate that Phase 208 performance benchmarks hold under load.

**Key Differences from Phase 208 Benchmarks:**
- **Phase 208**: Single-user benchmarks establishing targets (<1ms cache, <100ms API)
- **Phase 209**: Multi-user load testing validating targets under concurrent load (100-1000 users)

## Prerequisites

1. **Locust installed** (already in requirements-testing.txt):
   ```bash

   pip install locust>=2.15.0

   ```

2. **Application running**:
   ```bash

   cd backend

   python -m uvicorn main:app --host 0.0.0.0 --port 8000

   ```

3. **Test database** (optional but recommended):
   ```bash

   export DATABASE_URL=sqlite:///./atom_load_test.db

   ```

## Running Locust

### Interactive Mode (Web UI)

Start Locust with web UI for real-time monitoring:

```bash

cd backend

locust -f tests/load/locustfile.py

```

Then open http://localhost:8089 in your browser.

**Web UI Features:**
- Real-time request rate (RPS) monitoring
- Response time percentiles (P50, P95, P99)
- Failure rate tracking
- User count adjustment during test
- Stop/start test control

**Default Settings:**
- Host: http://localhost:8000
- Web UI Port: 8089
- Default Users: Start with 100 users
- Spawn Rate: 10 users/second

### Headless Mode (CI/CD)

Run load tests without web UI for automation:

```bash

cd backend

locust -f tests/load/locustfile.py --headless \

  -u 100 \              # 100 concurrent users

  -r 10 \               # Spawn 10 users/second

  -t 5m \               # Run for 5 minutes

  --html tests/load/reports/load-test-report.html \

  --json tests/load/reports/load-test-results.json

```

**Recommended Load Test Profiles:**

| Profile | Users | Duration | Purpose |
|---------|-------|----------|---------|
| Smoke Test | 50 | 2m | Quick validation, CI/CD |
| Standard Load | 100 | 5m | Normal traffic simulation |
| Peak Load | 500 | 10m | Peak traffic validation |
| Stress Test | 1000 | 15m | Identify breaking point |

### Custom Port (Avoid Conflicts)

If port 8089 is in use:

```bash

locust -f tests/load/locustfile.py --web-port=8090

```

## User Scenarios

### 1. AtomAPIUser (Base User)

**Purpose**: Basic API interactions with health checks

**Tasks:**
- Health check (weight: 1) - GET /health/live

**Wait Time**: 1-3 seconds between tasks

**When to Use**: Baseline health check performance

### 2. AgentAPIUser

**Purpose**: Simulate agent management operations

**Tasks:**
- List agents (weight: 5) - GET /api/v1/agents
- Get agent (weight: 3) - GET /api/v1/agents/{id}
- Create agent (weight: 1) - POST /api/v1/agents

**Wait Time**: 1-3 seconds between tasks

**Phase 208 Targets:**
- List agents: <50ms
- Get agent: <50ms
- Create agent: <100ms

**When to Use**: Testing agent CRUD performance

### 3. WorkflowExecutionUser

**Purpose**: Simulate workflow execution operations

**Tasks:**
- Execute workflow (weight: 2) - POST /api/v1/workflows/{id}/execute
- List workflows (weight: 1) - GET /api/v1/workflows

**Wait Time**: 2-5 seconds (longer for workflow execution)

**Phase 208 Targets:**
- Execute workflow: <100ms
- List workflows: <50ms

**When to Use**: Testing workflow performance under load

### 4. GovernanceCheckUser

**Purpose**: Simulate governance permission checks

**Tasks:**
- Check permission (weight: 4) - POST /api/agent-governance/check-permission
- Get cache stats (weight: 2) - GET /api/agent-governance/cache-stats

**Wait Time**: 1-3 seconds between tasks

**Phase 208 Targets:**
- Cached permission check: <1ms
- Cache stats: <50ms

**When to Use**: Testing governance cache performance

### 5. EpisodeAPIUser

**Purpose**: Simulate episodic memory retrieval

**Tasks:**
- List episodes (weight: 3) - GET /api/v1/episodes
- Get episode (weight: 2) - GET /api/v1/episodes/{id}

**Wait Time**: 1-3 seconds between tasks

**Phase 208 Targets:**
- List episodes: <50ms
- Get episode: <50ms

**When to Use**: Testing episode retrieval performance

## Critical Endpoints

| Endpoint | Method | Purpose | Weight | Phase 208 Target |
|----------|--------|---------|--------|------------------|
| /health/live | GET | Health check | 1 | <10ms |
| /api/v1/agents | GET | List agents | 5 | <50ms |
| /api/v1/agents/{id} | GET | Get agent | 3 | <50ms |
| /api/v1/agents | POST | Create agent | 1 | <100ms |
| /api/v1/workflows/{id}/execute | POST | Execute workflow | 2 | <100ms |
| /api/v1/workflows | GET | List workflows | 1 | <50ms |
| /api/agent-governance/check-permission | POST | Check permission | 4 | <1ms (cached) |
| /api/agent-governance/cache-stats | GET | Cache stats | 2 | <50ms |
| /api/v1/episodes | GET | List episodes | 3 | <50ms |
| /api/v1/episodes/{id} | GET | Get episode | 2 | <50ms |

## Interpreting Results

### Key Metrics

**Requests Per Second (RPS):**
- Measure of throughput
- Higher is better (indicates capacity)
- Target: Maintain RPS as user count increases

**Response Time Percentiles:**
- **P50 (Median)**: 50% of requests complete faster than this
- **P95**: 95% of requests complete faster than this (SLA target)
- **P99**: 99% of requests complete faster than this (tail latency)

**Failure Rate:**
- Percentage of failed requests (non-2xx status codes)
- Target: <1% failure rate
- Common failures: 500 (server error), 503 (service unavailable)

### Example Output

```

Name                                                          # reqs      # fails |    Avg     Min     Max    Med |   req/s  failures/s

---------------------------------------------------------------------------------------------------------------------------------------

GET /health/live                                                  150     0(0.00%) |      8       5      15       8 |   10.00        0.00

GET /api/v1/agents                                                 75     0(0.00%) |     45      20      80      42 |    5.00        0.00

POST /api/v1/agents                                                 5     0(0.00%) |     95      70     120      90 |    0.33        0.00

---------------------------------------------------------------------------------------------------------------------------------------

Aggregate                                                          230     0(0.00%) |     32       5     120      20 |   15.33        0.00



Response time percentiles (approximate)

  50%      20ms

  66%      25ms

  75%      30ms

  80%      35ms

  90%      50ms

  95%      70ms

  98%      90ms

  99%     110ms

 100%     120ms (longest request)

```

### Performance Indicators

**Good Performance:**
- P95 response time < Phase 208 targets (e.g., <50ms for agents)
- Failure rate <1%
- RPS scales linearly with user count
- No response time spikes as user count increases

**Performance Issues:**
- P95 response time increases with user count (bottleneck)
- Failure rate >5% (capacity limit)
- RPS plateaus or decreases (system overload)
- Response time spikes during test (resource exhaustion)

## Troubleshooting

### Server Not Running

**Symptom:** Connection refused errors

**Solution:**
```bash

# Check if server is running

curl http://localhost:8000/health/live



# Start server if not running

cd backend

python -m uvicorn main:app --host 0.0.0.0 --port 8000

```

### Authentication Failures

**Symptom:** 401 Unauthorized errors

**Solution:**
- Load tests use hardcoded credentials (`load_test@example.com`)
- Ensure test user exists in database
- Check authentication endpoint is working:
  ```bash

  curl -X POST http://localhost:8000/api/v1/auth/login \

    -H "Content-Type: application/json" \

    -d '{"email": "load_test@example.com", "password": "test_password_123"}'

  ```

### Port Conflicts

**Symptom:** "Address already in use" error

**Solution:**
```bash

# Use different port for Locust web UI

locust -f tests/load/locustfile.py --web-port=8090

```

### Database Connection Pool Exhaustion

**Symptom:** "Connection pool exhausted" errors, timeouts

**Solution:**
```bash

# Increase connection pool size

export SQLALCHEMY_POOL_SIZE=20

export SQLALCHEMY_MAX_OVERFLOW=40

export SQLALCHEMY_POOL_TIMEOUT=30



# Restart server with new settings

python -m uvicorn main:app --host 0.0.0.0 --port 8000

```

### High Failure Rate

**Symptom:** >5% failure rate with 500 errors

**Possible Causes:**
1. **Database overload**: Reduce concurrent users, increase pool size
2. **Memory pressure**: Check server memory usage, reduce user count
3. **Rate limiting**: Check if API has rate limits configured
4. **External service failures**: Check LLM provider, external APIs

**Debugging:**
```bash

# Check server logs

tail -f logs/atom.log | grep ERROR



# Monitor server resources

htop  # or top on macOS



# Check database connections

# For PostgreSQL:

psql -c "SELECT count(*) FROM pg_stat_activity;"

```

### Slow Response Times

**Symptom:** P95 > 2x Phase 208 targets

**Possible Causes:**
1. **Cache misses**: Cold cache, low hit rate
2. **Database queries**: Missing indexes, N+1 queries
3. **Network latency**: Local vs remote database
4. **Resource contention**: CPU, memory, disk I/O

**Debugging:**
```bash

# Check cache hit rate

curl http://localhost:8000/api/agent-governance/cache-stats



# Profile database queries

# Enable query logging in SQLAlchemy

export SQLALCHEMY_ECHO=true



# Run with profiling

python -m cProfile -o profile.stats -m uvicorn main:app

```

## CI Integration

### GitHub Actions Workflow

```yaml

name: Load Tests



on:

  schedule:

    # Run daily at 2 AM UTC

    - cron: '0 2 * * *'

  pull_request:

    paths:

      - 'backend/core/**'

      - 'backend/api/**'



jobs:

  load-test:

    name: Run Load Tests

    runs-on: ubuntu-large



    steps:

      - name: Checkout code

        uses: actions/checkout@v4



      - name: Set up Python

        uses: actions/setup-python@v5

        with:

          python-version: '3.11'



      - name: Install dependencies

        run: |

          cd backend

          pip install -r requirements.txt

          pip install -r requirements-testing.txt



      - name: Start application

        run: |

          cd backend

          python -m uvicorn main:app --host 0.0.0.0 --port 8000 &

          sleep 10



      - name: Run load tests

        run: |

          cd backend

          locust -f tests/load/locustfile.py --headless \

            -u 100 \

            -r 10 \

            -t 5m \

            --html tests/load/reports/load-test-report.html \

            --json tests/load/reports/load-test-results.json



      - name: Upload load test report

        uses: actions/upload-artifact@v4

        with:

          name: load-test-report

          path: backend/tests/load/reports/load-test-report.html

```

### Quick Smoke Test for CI

For faster CI feedback, run a 2-minute smoke test:

```bash

locust -f tests/load/locustfile.py --headless \

  -u 50 \              # Fewer users for speed

  -r 5 \               # Slower spawn rate

  -t 2m \              # Shorter duration

  --exit-code-on-error  # Fail CI if load test fails

```

## Best Practices

1. **Warm up the cache**: Run for 1-2 minutes before collecting metrics
2. **Start small**: Begin with 50 users, scale up gradually
3. **Monitor resources**: Watch CPU, memory, database connections during test
4. **Use realistic data**: Test with production-like data volumes
5. **Run multiple times**: Performance can vary due to system load
6. **Compare to baseline**: Track performance over time to detect regressions
7. **Test in staging**: Never run load tests in production without limits

## Next Steps

After running load tests:
1. Review HTML report for detailed metrics
2. Compare P95 times to Phase 208 targets
3. Identify bottlenecks (database, cache, network)
4. Optimize slow endpoints
5. Re-run load tests to validate improvements
6. Update baseline metrics if performance improved

## References

- **Phase 208 Benchmarks**: `.planning/phases/208-integration-performance-testing/208-07-PERFORMANCE-METRICS.md`
- **Locust Documentation**: https://docs.locust.io/
- **Load Testing Research**: `.planning/phases/209-load-stress-testing/209-RESEARCH.md`
- **Monitoring Setup**: `backend/docs/MONITORING_SETUP.md`