Skip to content

Instantly share code, notes, and snippets.

@mvdbeek
Last active October 31, 2025 15:45
Show Gist options
  • Select an option

  • Save mvdbeek/6a2a0e473fc85e7f4876f2d95d7e474b to your computer and use it in GitHub Desktop.

Select an option

Save mvdbeek/6a2a0e473fc85e7f4876f2d95d7e474b to your computer and use it in GitHub Desktop.
Rate limit test
=========================================
Galaxy API Rate Limiting Test (Parallel)
=========================================
Target: https://test.galaxyproject.org
Endpoint: https://test.galaxyproject.org/api/version
Temp dir: /var/folders/df/6xqpqpcd7h73b6jpx9t6cwhw0000gn/T/tmp.9BmqdrrwVf
=== Test 1: Burst Capacity Test ===
Testing burst capacity with 0c918d2fbb...
Test: 60 parallel requests with key1_burst
----------------------------------------------
Launching 60 requests...
Results:
✓ Success (200): 51
✗ Rate Limited (429): 9
⏱ Avg response time: 588.2ms
Waiting 15 seconds for rate limit to fully refill...
=== Test 2: Sustained Load Test ===
Sending requests in waves to test rate refill...
Wave 1: 60 parallel requests...
Waiting 5 seconds for rate limit to refill...
Wave 2: 30 parallel requests (should have ~20 tokens refilled @ 4r/s)...
Wave 1 success: 51/60
Wave 2 success: 22/30
=== Test 3: Independent Rate Limit Test ===
Testing if API keys have independent rate limits...
Waiting 15 seconds for API Key 1 to fully refill...
Step 1: Exhausting API Key 1...
Test: 60 parallel requests with key1_exhaust
----------------------------------------------
Launching 60 requests...
Results:
✓ Success (200): 51
✗ Rate Limited (429): 9
⏱ Avg response time: 455.0ms
Step 2: Testing API Key 2 (should have full burst if independent)...
Test: 60 parallel requests with key2_fresh
----------------------------------------------
Launching 60 requests...
Results:
✓ Success (200): 51
✗ Rate Limited (429): 9
⏱ Avg response time: 462.7ms
Independence Analysis:
✓ PASS: API keys have independent rate limits
Key 2 handled 51 requests after Key 1 was exhausted
=== Test 4: Session Cookie Rate Limiting ===
Testing with session cookie (should use cookie as zone key)...
Waiting 15 seconds for rate limit to fully refill...
Testing Session Cookie 1 with burst test...
Test: 60 parallel requests with session1_burst
----------------------------------------------
Launching 60 requests...
Results:
✓ Success (200): 51
✗ Rate Limited (429): 9
⏱ Avg response time: 501.1ms
Testing Session Cookie 2 immediately (should have full burst if independent)...
Test: 60 parallel requests with session2_fresh
----------------------------------------------
Launching 60 requests...
Results:
✓ Success (200): 51
✗ Rate Limited (429): 9
⏱ Avg response time: 486.4ms
Session Cookie Independence Analysis:
✓ PASS: Session cookies have independent rate limits
Cookie 2 handled 51 requests after Cookie 1 was exhausted
=== Test 5: IP-Based Rate Limiting ===
Testing without API key or cookie (should use IP address)...
Waiting 15 seconds for rate limit to fully refill...
Success (200): 51
Rate Limited (429): 9
=========================================
SUMMARY
=========================================
Configuration:
- Rate: 4 requests/second
- Burst: 50
- Zone key priority: API key > Session cookie > IP
- Exempted: /api/upload/resumable_upload, /api/job_files
Expected behavior with burst=50:
- First ~50-54 parallel requests: SUCCESS (burst bucket)
- Subsequent requests: RATE LIMITED (429)
- After waiting: ~4 requests/second refill rate
Recommendations:
✓ Burst capacity appears correct (~50)
Test 1 got 51 successful requests
✓ Rate refill appears to work correctly
Test completed. Results saved in: /var/folders/df/6xqpqpcd7h73b6jpx9t6cwhw0000gn/T/tmp.9BmqdrrwVf
To preserve results, copy the directory before script exits.
#!/bin/bash
#
# Parallel Rate Limiting Test for Galaxy API
# Tests rate limiting with concurrent requests to verify limits apply correctly
#
# Rate limit configuration:
# - Rate: 4 requests/second
# - Burst: 50
# - Key: API key (if present) > session cookie > IP address
#
# Usage: ./test_rate_limiting_parallel.sh <galaxy_url> <api_key_1> [api_key_2] [session_cookie_1] [session_cookie_2]
set -e
if [ $# -lt 2 ]; then
echo "Usage: $0 <galaxy_url> <api_key_1> [api_key_2] [session_cookie_1] [session_cookie_2]"
echo ""
echo "Examples:"
echo " $0 https://test.galaxyproject.org api_key_1"
echo " $0 https://test.galaxyproject.org api_key_1 api_key_2"
echo " $0 https://test.galaxyproject.org api_key_1 '' session_cookie_1"
echo " $0 https://test.galaxyproject.org api_key_1 api_key_2 session_cookie_1 session_cookie_2"
exit 1
fi
GALAXY_URL="$1"
API_KEY_1="$2"
API_KEY_2="${3:-}"
SESSION_COOKIE_1="${4:-}"
SESSION_COOKIE_2="${5:-}"
TEST_ENDPOINT="${GALAXY_URL}/api/version"
# Colors for output
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# Create temporary directory for results
TEMP_DIR=$(mktemp -d)
trap "rm -rf ${TEMP_DIR}" EXIT
echo "========================================="
echo "Galaxy API Rate Limiting Test (Parallel)"
echo "========================================="
echo "Target: ${GALAXY_URL}"
echo "Endpoint: ${TEST_ENDPOINT}"
echo "Temp dir: ${TEMP_DIR}"
echo ""
# Function to make a single request and record result
make_request() {
local api_key="$1"
local index="$2"
local output_file="$3"
local session_cookie="${4:-}"
local start_time=$(date +%s.%N)
# Build curl command based on what's provided
local curl_args=()
if [ -n "$api_key" ]; then
curl_args+=(-H "x-api-key: ${api_key}")
fi
if [ -n "$session_cookie" ]; then
curl_args+=(-b "galaxysession=${session_cookie}")
fi
local http_code=$(curl -s -o /dev/null -w "%{http_code}" \
--max-time 10 \
"${curl_args[@]}" \
"${TEST_ENDPOINT}" 2>/dev/null || echo "000")
local end_time=$(date +%s.%N)
# Calculate duration in milliseconds
local duration=$(echo "($end_time - $start_time) * 1000" | bc)
echo "${index},${http_code},${duration}" >> "${output_file}"
}
# Function to run parallel requests
run_parallel_test() {
local api_key="$1"
local num_requests="$2"
local key_name="$3"
local session_cookie="${4:-}"
local output_file="${TEMP_DIR}/${key_name}.csv"
echo "Test: ${num_requests} parallel requests with ${key_name}"
echo "----------------------------------------------"
# Launch all requests in parallel
echo "Launching ${num_requests} requests..."
for i in $(seq 1 $num_requests); do
make_request "${api_key}" "$i" "${output_file}" "${session_cookie}" &
done
# Wait for all background jobs to complete
wait
# Analyze results
local total=$(wc -l < "${output_file}" | tr -d ' ')
local success=$(grep -c ",200," "${output_file}" || true)
local limited=$(grep -c ",429," "${output_file}" || true)
local errors=$(grep -c ",000," "${output_file}" || true)
local other=$((total - success - limited - errors))
echo " Results:"
echo " ✓ Success (200): ${success}"
echo " ✗ Rate Limited (429): ${limited}"
if [ $errors -gt 0 ]; then
echo " ! Errors/Timeouts: ${errors}"
fi
if [ $other -gt 0 ]; then
echo " ? Other responses: ${other}"
fi
# Calculate average response time for successful requests
if [ $success -gt 0 ]; then
local avg_duration=$(grep ",200," "${output_file}" | cut -d',' -f3 | \
awk '{sum+=$1; count++} END {if(count>0) printf "%.1f", sum/count; else print "0"}')
echo " ⏱ Avg response time: ${avg_duration}ms"
fi
echo ""
}
# Test 1: Single API key with burst test
echo -e "${BLUE}=== Test 1: Burst Capacity Test ===${NC}"
echo "Testing burst capacity with ${API_KEY_1:0:10}..."
echo ""
run_parallel_test "${API_KEY_1}" 60 "key1_burst"
# Expected: ~50-54 successful requests (burst=50 + rate refill during execution)
# Rest should be rate limited (429)
# Wait for rate limit to refill before next test
echo "Waiting 15 seconds for rate limit to fully refill..."
sleep 15
echo ""
# Test 2: Sustained load over time
echo -e "${BLUE}=== Test 2: Sustained Load Test ===${NC}"
echo "Sending requests in waves to test rate refill..."
echo ""
KEY1_SUSTAINED="${TEMP_DIR}/key1_sustained.csv"
echo "Wave 1: 60 parallel requests..."
for i in $(seq 1 60); do
make_request "${API_KEY_1}" "wave1_$i" "${KEY1_SUSTAINED}" "" &
done
wait
echo "Waiting 5 seconds for rate limit to refill..."
sleep 5
echo "Wave 2: 30 parallel requests (should have ~20 tokens refilled @ 4r/s)..."
for i in $(seq 1 30); do
make_request "${API_KEY_1}" "wave2_$i" "${KEY1_SUSTAINED}" "" &
done
wait
# Analyze sustained test
wave1_success=$(grep "wave1_.*,200," "${KEY1_SUSTAINED}" | wc -l | tr -d ' ')
wave2_success=$(grep "wave2_.*,200," "${KEY1_SUSTAINED}" | wc -l | tr -d ' ')
echo " Wave 1 success: ${wave1_success}/60"
echo " Wave 2 success: ${wave2_success}/30"
echo ""
# Test 3: Independent API key limits (if second key provided)
if [ -n "${API_KEY_2}" ]; then
echo -e "${BLUE}=== Test 3: Independent Rate Limit Test ===${NC}"
echo "Testing if API keys have independent rate limits..."
echo ""
# Wait for key 1 to refill first
echo "Waiting 15 seconds for API Key 1 to fully refill..."
sleep 15
echo ""
# Exhaust key 1
echo "Step 1: Exhausting API Key 1..."
run_parallel_test "${API_KEY_1}" 60 "key1_exhaust"
# Immediately test key 2
echo "Step 2: Testing API Key 2 (should have full burst if independent)..."
run_parallel_test "${API_KEY_2}" 60 "key2_fresh"
# Compare results
key1_success=$(grep -c ",200," "${TEMP_DIR}/key1_exhaust.csv" || true)
key2_success=$(grep -c ",200," "${TEMP_DIR}/key2_fresh.csv" || true)
echo -e "${BLUE}Independence Analysis:${NC}"
if [ $key2_success -ge 45 ]; then
echo -e " ${GREEN}✓ PASS: API keys have independent rate limits${NC}"
echo " Key 2 handled ${key2_success} requests after Key 1 was exhausted"
elif [ $key2_success -lt 10 ]; then
echo -e " ${RED}✗ FAIL: API keys appear to share rate limits${NC}"
echo " Key 2 only handled ${key2_success} requests (expected ~50)"
else
echo -e " ${YELLOW}⚠ BORDERLINE: Key 2 handled ${key2_success} requests${NC}"
echo " Expected ~50 if fully independent"
fi
echo ""
fi
# Test 4: Session cookie rate limiting (if provided)
if [ -n "${SESSION_COOKIE_1}" ]; then
echo -e "${BLUE}=== Test 4: Session Cookie Rate Limiting ===${NC}"
echo "Testing with session cookie (should use cookie as zone key)..."
echo ""
# Wait for any previous limits to clear
echo "Waiting 15 seconds for rate limit to fully refill..."
sleep 15
echo ""
echo "Testing Session Cookie 1 with burst test..."
run_parallel_test "" 60 "session1_burst" "${SESSION_COOKIE_1}"
# If second session cookie provided, test independence
if [ -n "${SESSION_COOKIE_2}" ]; then
echo ""
echo "Testing Session Cookie 2 immediately (should have full burst if independent)..."
run_parallel_test "" 60 "session2_fresh" "${SESSION_COOKIE_2}"
session1_success=$(grep -c ",200," "${TEMP_DIR}/session1_burst.csv" || true)
session2_success=$(grep -c ",200," "${TEMP_DIR}/session2_fresh.csv" || true)
echo -e "${BLUE}Session Cookie Independence Analysis:${NC}"
if [ $session2_success -ge 45 ]; then
echo -e " ${GREEN}✓ PASS: Session cookies have independent rate limits${NC}"
echo " Cookie 2 handled ${session2_success} requests after Cookie 1 was exhausted"
elif [ $session2_success -lt 10 ]; then
echo -e " ${RED}✗ FAIL: Session cookies appear to share rate limits${NC}"
echo " Cookie 2 only handled ${session2_success} requests (expected ~50)"
else
echo -e " ${YELLOW}⚠ BORDERLINE: Cookie 2 handled ${session2_success} requests${NC}"
echo " Expected ~50 if fully independent"
fi
fi
echo ""
fi
# Test 5: IP-based rate limiting (no API key or cookie)
test_num=4
if [ -n "${SESSION_COOKIE_1}" ]; then
test_num=5
fi
echo -e "${BLUE}=== Test ${test_num}: IP-Based Rate Limiting ===${NC}"
echo "Testing without API key or cookie (should use IP address)..."
echo ""
# Wait for previous tests to clear
echo "Waiting 15 seconds for rate limit to fully refill..."
sleep 15
echo ""
IP_OUTPUT="${TEMP_DIR}/ip_based.csv"
for i in $(seq 1 60); do
(
start_time=$(date +%s.%N)
http_code=$(curl -s -o /dev/null -w "%{http_code}" \
--max-time 10 \
"${TEST_ENDPOINT}" 2>/dev/null || echo "000")
end_time=$(date +%s.%N)
duration=$(echo "($end_time - $start_time) * 1000" | bc)
echo "${i},${http_code},${duration}" >> "${IP_OUTPUT}"
) &
done
wait
ip_success=$(grep -c ",200," "${IP_OUTPUT}" || true)
ip_limited=$(grep -c ",429," "${IP_OUTPUT}" || true)
echo " Success (200): ${ip_success}"
echo " Rate Limited (429): ${ip_limited}"
echo ""
# Final Summary
echo "========================================="
echo "SUMMARY"
echo "========================================="
echo ""
echo "Configuration:"
echo " - Rate: 4 requests/second"
echo " - Burst: 50"
echo " - Zone key priority: API key > Session cookie > IP"
echo " - Exempted: /api/upload/resumable_upload, /api/job_files"
echo ""
echo "Expected behavior with burst=50:"
echo " - First ~50-54 parallel requests: SUCCESS (burst bucket)"
echo " - Subsequent requests: RATE LIMITED (429)"
echo " - After waiting: ~4 requests/second refill rate"
echo ""
# Provide recommendations
echo "Recommendations:"
# Get the burst test results (from Test 1)
burst_success=$(grep -c ",200," "${TEMP_DIR}/key1_burst.csv" || true)
if [ $burst_success -ge 48 ] && [ $burst_success -le 56 ]; then
echo -e " ${GREEN}✓ Burst capacity appears correct (~50)${NC}"
echo " Test 1 got ${burst_success} successful requests"
elif [ $burst_success -lt 45 ]; then
echo -e " ${YELLOW}⚠ Burst capacity seems low (got ${burst_success}, expected ~50)${NC}"
echo " Check nginx burst configuration"
elif [ $burst_success -gt 56 ]; then
echo -e " ${YELLOW}⚠ More requests succeeded than expected (got ${burst_success})${NC}"
echo " Rate limiting may not be applied correctly"
fi
if [ $wave2_success -ge 15 ] && [ $wave2_success -le 30 ]; then
echo -e " ${GREEN}✓ Rate refill appears to work correctly${NC}"
elif [ $wave2_success -lt 10 ]; then
echo -e " ${YELLOW}⚠ Rate refill seems slow (got ${wave2_success}, expected ~20)${NC}"
fi
echo ""
echo "Test completed. Results saved in: ${TEMP_DIR}"
echo "To preserve results, copy the directory before script exits."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment