📦 EqualifyEverything / equalify-reflow

📄 test-rate-limits.md · 59 lines
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# How to test rate limits locally

The running stack respects the configured limits. To observe a 429 response, submit faster than the per-IP tier permits.

## Trigger a submission 429

The default per-IP submission limit is 10 requests per hour. Eleven requests from the same `X-Forwarded-For` IP should give you one 429:

```bash
for i in {1..11}; do
  curl -X POST http://localhost:8080/api/v1/documents/submit \
    -F "file=@tests/fixtures/small.pdf" \
    -H "X-API-Key: $API_KEY" \
    -H "X-Forwarded-For: 203.0.113.1" \
    -w "\n%{http_code}\n" \
    -o /dev/null -s
done
# Expected: ten 201s, one 429
```

## Inspect rate-limit state directly

```bash
make redis-cli
> ZRANGE eq-pdf:ratelimit:submit:ip:203.0.113.1 0 -1 WITHSCORES
> TTL   eq-pdf:ratelimit:submit:ip:203.0.113.1
```

## Clear a tier for a specific IP

If you've tripped a limit during development:

```bash
make redis-cli
> DEL eq-pdf:ratelimit:submit:ip:203.0.113.1
```

Or programmatically from the Python shell (`make shell`):

```python
from src.services.rate_limit_service import RateLimitService
await rate_limiter.reset_rate_limit("203.0.113.1", "submit")
```

## Verify fail-open behaviour

Stop Redis and confirm the rate limiter allows requests (logs should show `rate_limiter_unavailable`):

```bash
docker compose stop redis
curl -X POST http://localhost:8080/api/v1/documents/submit \
  -F "file=@tests/fixtures/small.pdf" \
  -H "X-API-Key: $API_KEY"
# Expected: 201, plus a WARN log line noting the rate limiter failed open
docker compose start redis
```

For the rationale behind fail-open, see [rate limiting design](../explanation/rate-limiting.md).