Skip to content

Commit 50a7a76

Browse files
committed
feat(benchmarks): add flexible queue mode testing with emulator support
- Update run_benchmarks.sh to accept queue_mode argument (async|pubsub) - Results now organized by queue mode: results/{queue_mode}/ - Add Pub/Sub + GCS emulator setup instructions - Document AsyncQueue vs PubSub trade-offs and characteristics - Enable comparative testing: single-server vs distributed architectures - Include emulator commands for local PubSub benchmarking
1 parent ab6e4fa commit 50a7a76

2 files changed

Lines changed: 144 additions & 9 deletions

File tree

benchmarks/README.md

Lines changed: 93 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,49 @@ This directory contains load testing scenarios for validating EventKit's perform
66

77
### 1. Start EventKit
88

9+
Choose your queue mode:
10+
11+
**AsyncQueue Mode (Single-Server, In-Process)**:
12+
```bash
13+
# Terminal 1: Start EventKit API with AsyncQueue
14+
GCP_PROJECT_ID=eventkit-benchmark \
15+
GCP_GCS_BUCKET=eventkit-events \
16+
STORAGE_EMULATOR_HOST=http://localhost:4443 \
17+
EVENTKIT_RING_BUFFER_ENABLED=true \
18+
EVENTKIT_QUEUE_MODE=async \
19+
uv run uvicorn eventkit.api.app:app --host=0.0.0.0 --port=8000
20+
```
21+
22+
**PubSub Mode (Distributed, External Queue)**:
923
```bash
10-
# Terminal 1: Start EventKit API
11-
cd /path/to/eventkit
12-
uvicorn eventkit.api.app:app --host=0.0.0.0 --port=8000
24+
# Terminal 1: Start Pub/Sub + GCS emulators
25+
docker compose up -d pubsub-emulator gcs-emulator
26+
27+
# Terminal 2: Start EventKit API with PubSub
28+
GCP_PROJECT_ID=eventkit-benchmark \
29+
GCP_GCS_BUCKET=eventkit-events \
30+
PUBSUB_EMULATOR_HOST=localhost:8085 \
31+
STORAGE_EMULATOR_HOST=http://localhost:9023 \
32+
EVENTKIT_RING_BUFFER_ENABLED=true \
33+
EVENTKIT_QUEUE_MODE=pubsub \
34+
EVENTKIT_PUBSUB_TOPIC=eventkit-events \
35+
uv run uvicorn eventkit.api.app:app --host=0.0.0.0 --port=8000
36+
37+
# Terminal 3: Start EventSubscriptionCoordinator workers
38+
# (Implementation specific - see streaming/coordinator.py for examples)
1339
```
1440

1541
### 2. Run All Benchmarks
1642

1743
```bash
18-
# Terminal 2: Run benchmark suite
19-
./benchmarks/run_benchmarks.sh
44+
# Test AsyncQueue mode
45+
./benchmarks/run_benchmarks.sh async
46+
47+
# Or test PubSub mode
48+
./benchmarks/run_benchmarks.sh pubsub
2049
```
2150

22-
This will run all scenarios and save results to `benchmarks/results/`.
51+
Results will be saved to `benchmarks/results/{queue_mode}/`.
2352

2453
## Manual Testing
2554

@@ -171,6 +200,63 @@ uv run memray run -o memory.bin \
171200
memray flamegraph memory.bin
172201
```
173202

203+
## Comparing Queue Modes
204+
205+
EventKit supports two queue modes with different trade-offs:
206+
207+
### AsyncQueue (Single-Server)
208+
**Best for**: Development, single-instance deployments
209+
210+
**Characteristics**:
211+
- In-process Python `asyncio.Queue`
212+
- Low latency (microseconds to enqueue)
213+
- No external dependencies
214+
- Simpler architecture
215+
- Limited to single server's resources
216+
217+
**Benchmark this to measure**:
218+
- Maximum throughput for single instance
219+
- Memory pressure under load
220+
- Ring buffer → queue → loader latency
221+
222+
### PubSub (Distributed)
223+
**Best for**: Production, horizontal scaling
224+
225+
**Characteristics**:
226+
- External queue (Google Cloud Pub/Sub)
227+
- Higher latency (milliseconds to publish)
228+
- Distributed processing
229+
- Horizontal scalability
230+
- More complex architecture
231+
232+
**Benchmark this to measure**:
233+
- Network overhead (API → Pub/Sub)
234+
- Multi-worker scalability
235+
- Fault tolerance (nack/redelivery)
236+
237+
### Running Comparisons
238+
239+
```bash
240+
# Benchmark AsyncQueue (single emulator needed)
241+
docker compose up -d gcs-emulator
242+
./benchmarks/run_benchmarks.sh async
243+
244+
# Benchmark PubSub (both emulators needed)
245+
docker compose up -d pubsub-emulator gcs-emulator
246+
./benchmarks/run_benchmarks.sh pubsub
247+
248+
# Compare results
249+
diff benchmarks/results/async/baseline.log \
250+
benchmarks/results/pubsub/baseline.log
251+
252+
# Stop emulators when done
253+
docker compose down
254+
```
255+
256+
**What to expect**:
257+
- **AsyncQueue**: Higher throughput, lower latency (no network hops)
258+
- **PubSub**: Lower throughput (network + serialization overhead), but horizontally scalable
259+
174260
## Configuration Tuning
175261

176262
Test different configurations by setting environment variables:
@@ -187,7 +273,7 @@ export EVENTKIT_RING_BUFFER_ENABLED=false
187273
export EVENTKIT_EVENT_LOADER_FLUSH_INTERVAL=60
188274

189275
# Run benchmarks
190-
./benchmarks/run_benchmarks.sh
276+
./benchmarks/run_benchmarks.sh async
191277
```
192278

193279
## Expected Results

benchmarks/run_benchmarks.sh

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,19 @@
44
#
55
# Runs all benchmark scenarios and collects results.
66
#
7+
# Usage:
8+
# ./benchmarks/run_benchmarks.sh [queue_mode]
9+
#
10+
# Arguments:
11+
# queue_mode: "async" (default) or "pubsub"
12+
#
13+
# Examples:
14+
# # Test AsyncQueue (single-server)
15+
# ./benchmarks/run_benchmarks.sh async
16+
#
17+
# # Test PubSub (distributed)
18+
# ./benchmarks/run_benchmarks.sh pubsub
19+
#
720

821
set -euo pipefail
922

@@ -14,14 +27,22 @@ YELLOW='\033[1;33m'
1427
NC='\033[0m' # No Color
1528

1629
# Configuration
30+
QUEUE_MODE="${1:-async}"
1731
HOST="${EVENTKIT_HOST:-http://localhost:8000}"
18-
RESULTS_DIR="benchmarks/results"
32+
RESULTS_DIR="benchmarks/results/${QUEUE_MODE}"
1933
DURATION="${DURATION:-60s}"
2034

35+
# Validate queue mode
36+
if [[ "$QUEUE_MODE" != "async" && "$QUEUE_MODE" != "pubsub" ]]; then
37+
echo "ERROR: Invalid queue mode '$QUEUE_MODE'. Must be 'async' or 'pubsub'"
38+
exit 1
39+
fi
40+
2141
echo -e "${BLUE}========================================${NC}"
2242
echo -e "${BLUE}EventKit Performance Benchmarks${NC}"
2343
echo -e "${BLUE}========================================${NC}"
2444
echo ""
45+
echo "Queue Mode: $QUEUE_MODE"
2546
echo "Host: $HOST"
2647
echo "Duration: $DURATION"
2748
echo "Results: $RESULTS_DIR"
@@ -59,7 +80,35 @@ run_scenario() {
5980
echo -e "${YELLOW}Checking if EventKit is running...${NC}"
6081
if ! curl -s "$HOST/health" > /dev/null 2>&1; then
6182
echo "ERROR: EventKit is not running at $HOST"
62-
echo "Start it with: uvicorn eventkit.api.app:app --host=0.0.0.0 --port=8000"
83+
echo ""
84+
echo "Start EventKit with the following configuration:"
85+
echo ""
86+
if [[ "$QUEUE_MODE" == "async" ]]; then
87+
echo " # AsyncQueue mode (single-server, in-process)"
88+
echo " GCP_PROJECT_ID=eventkit-benchmark \\"
89+
echo " GCP_GCS_BUCKET=eventkit-events \\"
90+
echo " STORAGE_EMULATOR_HOST=http://localhost:4443 \\"
91+
echo " EVENTKIT_RING_BUFFER_ENABLED=true \\"
92+
echo " EVENTKIT_QUEUE_MODE=async \\"
93+
echo " uv run uvicorn eventkit.api.app:app --host=0.0.0.0 --port=8000"
94+
else
95+
echo " # PubSub mode (distributed, external queue)"
96+
echo ""
97+
echo " # Start emulators"
98+
echo " docker compose up -d pubsub-emulator gcs-emulator"
99+
echo ""
100+
echo " # Start EventKit API"
101+
echo " GCP_PROJECT_ID=eventkit-benchmark \\"
102+
echo " GCP_GCS_BUCKET=eventkit-events \\"
103+
echo " PUBSUB_EMULATOR_HOST=localhost:8085 \\"
104+
echo " STORAGE_EMULATOR_HOST=http://localhost:9023 \\"
105+
echo " EVENTKIT_RING_BUFFER_ENABLED=true \\"
106+
echo " EVENTKIT_QUEUE_MODE=pubsub \\"
107+
echo " EVENTKIT_PUBSUB_TOPIC=eventkit-events \\"
108+
echo " uv run uvicorn eventkit.api.app:app --host=0.0.0.0 --port=8000"
109+
echo ""
110+
echo " Note: Ensure you have EventSubscriptionCoordinator workers running separately"
111+
fi
63112
exit 1
64113
fi
65114
echo -e "${GREEN}✓ EventKit is running${NC}"

0 commit comments

Comments
 (0)