From e72ba62568e541194498a90d4d7b02a334d9a60e Mon Sep 17 00:00:00 2001 From: Ankur Datta <64993082+ankur-arch@users.noreply.github.com> Date: Mon, 11 Aug 2025 17:22:41 +0600 Subject: [PATCH 1/5] fix: change rate limit key --- claim-db-worker/src/index.ts | 4 +++- create-db-worker/src/index.ts | 4 +++- tests/test-rate-limits.sh | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/claim-db-worker/src/index.ts b/claim-db-worker/src/index.ts index 328c8e4..b55ced0 100644 --- a/claim-db-worker/src/index.ts +++ b/claim-db-worker/src/index.ts @@ -30,7 +30,9 @@ function errorResponse(title: string, message: string, details?: string, status export default { async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise { // --- Rate limiting --- - const { success } = await env.CLAIM_DB_RATE_LIMITER.limit({ key: request.url }); + // Use client IP for consistent rate limiting across environments + const clientIP = request.headers.get('CF-Connecting-IP') || request.headers.get('X-Forwarded-For') || 'unknown'; + const { success } = await env.CLAIM_DB_RATE_LIMITER.limit({ key: clientIP }); if (!success) { return errorResponse('Rate Limit Exceeded', "We're experiencing high demand. Please try again later.", '', 429); diff --git a/create-db-worker/src/index.ts b/create-db-worker/src/index.ts index 038ec70..40a52fc 100644 --- a/create-db-worker/src/index.ts +++ b/create-db-worker/src/index.ts @@ -12,7 +12,9 @@ export { DeleteDbWorkflow }; export default { async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise { // --- Rate limiting --- - const { success } = await env.CREATE_DB_RATE_LIMITER.limit({ key: request.url }); + // Use client IP for consistent rate limiting across environments + const clientIP = request.headers.get('CF-Connecting-IP') || request.headers.get('X-Forwarded-For') || 'unknown'; + const { success } = await env.CREATE_DB_RATE_LIMITER.limit({ key: clientIP }); if (!success) { return new Response(`429 Failure - rate limit exceeded for ${request.url}`, { status: 429 }); diff --git a/tests/test-rate-limits.sh b/tests/test-rate-limits.sh index a17f514..0bb14e4 100755 --- a/tests/test-rate-limits.sh +++ b/tests/test-rate-limits.sh @@ -5,8 +5,8 @@ # Default values TEST_COUNT=${1:-110} -CREATE_DB_URL=${2:-"http://127.0.0.1:8787"} -CLAIM_DB_URL=${3:-"http://127.0.0.1:9999"} +CREATE_DB_URL=${2:-"https://create-db-temp.prisma.io"} +CLAIM_DB_URL=${3:-"https://create-db.prisma.io"} echo "🧪 Testing Rate Limits" echo "======================" From fb9fea4bd8e44ffb9342b0abc2868525a3db02e5 Mon Sep 17 00:00:00 2001 From: Ankur Datta <64993082+ankur-arch@users.noreply.github.com> Date: Mon, 11 Aug 2025 20:32:26 +0600 Subject: [PATCH 2/5] fix: reduce rate limit --- claim-db-worker/src/index.ts | 4 ++-- claim-db-worker/wrangler.jsonc | 2 +- create-db-worker/src/index.ts | 7 +++++-- create-db-worker/wrangler.jsonc | 2 +- tests/test-rate-limits.sh | 20 +++++++++++++++----- 5 files changed, 24 insertions(+), 11 deletions(-) diff --git a/claim-db-worker/src/index.ts b/claim-db-worker/src/index.ts index b55ced0..d9baaef 100644 --- a/claim-db-worker/src/index.ts +++ b/claim-db-worker/src/index.ts @@ -31,8 +31,8 @@ export default { async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise { // --- Rate limiting --- // Use client IP for consistent rate limiting across environments - const clientIP = request.headers.get('CF-Connecting-IP') || request.headers.get('X-Forwarded-For') || 'unknown'; - const { success } = await env.CLAIM_DB_RATE_LIMITER.limit({ key: clientIP }); + const clientIP = request.headers.get('x-agent') || request.headers.get('cf-connecting-ip'); + const { success } = await env.CLAIM_DB_RATE_LIMITER.limit({ key: clientIP! }); if (!success) { return errorResponse('Rate Limit Exceeded', "We're experiencing high demand. Please try again later.", '', 429); diff --git a/claim-db-worker/wrangler.jsonc b/claim-db-worker/wrangler.jsonc index ff41a1f..b7544a8 100644 --- a/claim-db-worker/wrangler.jsonc +++ b/claim-db-worker/wrangler.jsonc @@ -24,7 +24,7 @@ "type": "ratelimit", "namespace_id": "1006", "simple": { - "limit": 100, + "limit": 10, "period": 60, }, }, diff --git a/create-db-worker/src/index.ts b/create-db-worker/src/index.ts index 40a52fc..715c67e 100644 --- a/create-db-worker/src/index.ts +++ b/create-db-worker/src/index.ts @@ -13,8 +13,11 @@ export default { async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise { // --- Rate limiting --- // Use client IP for consistent rate limiting across environments - const clientIP = request.headers.get('CF-Connecting-IP') || request.headers.get('X-Forwarded-For') || 'unknown'; - const { success } = await env.CREATE_DB_RATE_LIMITER.limit({ key: clientIP }); + const clientIP = request.headers.get('x-agent') || request.headers.get('cf-connecting-ip'); + + console.log(`Client IP: ${clientIP} - Request URL: ${request.url}`); + + const { success } = await env.CREATE_DB_RATE_LIMITER.limit({ key: clientIP! }); if (!success) { return new Response(`429 Failure - rate limit exceeded for ${request.url}`, { status: 429 }); diff --git a/create-db-worker/wrangler.jsonc b/create-db-worker/wrangler.jsonc index e7eee5d..4aca05f 100644 --- a/create-db-worker/wrangler.jsonc +++ b/create-db-worker/wrangler.jsonc @@ -27,7 +27,7 @@ "type": "ratelimit", "namespace_id": "1005", "simple": { - "limit": 100, + "limit": 10, "period": 60, }, }, diff --git a/tests/test-rate-limits.sh b/tests/test-rate-limits.sh index 0bb14e4..fac2060 100755 --- a/tests/test-rate-limits.sh +++ b/tests/test-rate-limits.sh @@ -1,18 +1,21 @@ #!/bin/bash # Test Rate Limits Script -# Usage: ./tests/test-rate-limits.sh [test_count] [create_db_url] [claim_db_url] +# Usage: ./tests/test-rate-limits.sh [test_count] [create_db_url] [claim_db_url] [agent_id] # Default values TEST_COUNT=${1:-110} CREATE_DB_URL=${2:-"https://create-db-temp.prisma.io"} CLAIM_DB_URL=${3:-"https://create-db.prisma.io"} +AGENT_ID=${4:-"meow"} echo "🧪 Testing Rate Limits" echo "======================" echo "Test Count: $TEST_COUNT" echo "Create DB URL: $CREATE_DB_URL" echo "Claim DB URL: $CLAIM_DB_URL" +echo "Agent Header: X-Agent: $AGENT_ID" +echo "User-Agent: prisma-rate-limit-test/$AGENT_ID" echo "" # Function to test a worker @@ -32,8 +35,15 @@ test_worker() { for i in $(seq 1 $TEST_COUNT); do echo -n "Request $i/$TEST_COUNT: " - # Make the request and capture both response body and status code - response=$(curl -s -w "%{http_code}" -o /tmp/response_$i.json "$endpoint" 2>/dev/null) + # Make the request with unique agent headers and capture body + status code + response=$(curl -s \ + -H "x-agent: $AGENT_ID" \ + -H "x-Agent: $AGENT_ID" \ + -H "User-Agent: prisma-rate-limit-test/$AGENT_ID" \ + -w "%{http_code}" \ + -o /tmp/response_$i.json \ + "$endpoint" 2>/dev/null) + status_code=${response: -3} case $status_code in @@ -52,7 +62,7 @@ test_worker() { esac # Small delay between requests - sleep 0.1 + #sleep 0.05 done echo "" @@ -76,4 +86,4 @@ echo "- Later requests should be rate limited (429)" echo "- This confirms rate limiting is working correctly" echo "" echo "💡 To test with your actual deployed URLs, run:" -echo " ./tests/test-rate-limits.sh 110 https://create-db-temp.prisma.io https://create-db.prisma.io" \ No newline at end of file +echo " ./tests/test-rate-limits.sh 110 https://create-db-temp.prisma.io https://create-db.prisma.io my-local-agent" From ede3ab3fe21065666b26397a1a175a09ea991750 Mon Sep 17 00:00:00 2001 From: Ankur Datta <64993082+ankur-arch@users.noreply.github.com> Date: Tue, 12 Aug 2025 13:14:02 +0600 Subject: [PATCH 3/5] chore: add ray id for tracing --- claim-db-worker/src/index.ts | 19 ++++++++++++++++++- create-db-worker/src/index.ts | 18 ++++++++++++++++-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/claim-db-worker/src/index.ts b/claim-db-worker/src/index.ts index d9baaef..231b300 100644 --- a/claim-db-worker/src/index.ts +++ b/claim-db-worker/src/index.ts @@ -29,13 +29,30 @@ function errorResponse(title: string, message: string, details?: string, status export default { async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise { + // --- Custom KV Rate limiting --- + // --- Rate limiting --- // Use client IP for consistent rate limiting across environments const clientIP = request.headers.get('x-agent') || request.headers.get('cf-connecting-ip'); + const rayId = request.headers.get('cf-ray') || request.headers.get('x-ray-id') || 'unknown-ray-id'; + const { success } = await env.CLAIM_DB_RATE_LIMITER.limit({ key: clientIP! }); if (!success) { - return errorResponse('Rate Limit Exceeded', "We're experiencing high demand. Please try again later.", '', 429); + console.log(`Rate limit exceeded for IP: ${clientIP}. Ray ID: ${rayId}. Request blocked to prevent abuse.`); + return new Response( + JSON.stringify({ + error: 'Too Many Requests', + message: 'You have exceeded the allowed number of requests. Please wait before trying again.', + code: 429, + ip: clientIP, + rayId, + }), + { + status: 429, + headers: { 'Content-Type': 'application/json' }, + }, + ); } async function sendPosthogEvent(event: string, properties: Record) { diff --git a/create-db-worker/src/index.ts b/create-db-worker/src/index.ts index 715c67e..333115b 100644 --- a/create-db-worker/src/index.ts +++ b/create-db-worker/src/index.ts @@ -14,13 +14,27 @@ export default { // --- Rate limiting --- // Use client IP for consistent rate limiting across environments const clientIP = request.headers.get('x-agent') || request.headers.get('cf-connecting-ip'); + const rayId = request.headers.get('cf-ray') || request.headers.get('x-ray-id') || 'unknown-ray-id'; console.log(`Client IP: ${clientIP} - Request URL: ${request.url}`); const { success } = await env.CREATE_DB_RATE_LIMITER.limit({ key: clientIP! }); if (!success) { - return new Response(`429 Failure - rate limit exceeded for ${request.url}`, { status: 429 }); + console.log(`Rate limit exceeded for IP: ${clientIP}. Ray ID: ${rayId}. Request blocked to prevent abuse.`); + return new Response( + JSON.stringify({ + error: 'Too Many Requests', + message: 'You have exceeded the allowed number of requests. Please wait before trying again.', + code: 429, + ip: clientIP, + rayId, + }), + { + status: 429, + headers: { 'Content-Type': 'application/json' }, + }, + ); } const url = new URL(request.url); @@ -32,7 +46,7 @@ export default { status: 'success', service: 'create-db-worker', timestamp: Date.now(), - message: 'Rate limit test endpoint - if you see this, rate limiting passed', + message: 'Rate limit test endpoint', }), { status: 200, From 200574e8c208aed17ea0cbf1af81b72149209bf4 Mon Sep 17 00:00:00 2001 From: Ankur Datta <64993082+ankur-arch@users.noreply.github.com> Date: Tue, 12 Aug 2025 13:14:45 +0600 Subject: [PATCH 4/5] fix: clear comment --- claim-db-worker/src/index.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/claim-db-worker/src/index.ts b/claim-db-worker/src/index.ts index 231b300..a14ddd9 100644 --- a/claim-db-worker/src/index.ts +++ b/claim-db-worker/src/index.ts @@ -29,8 +29,6 @@ function errorResponse(title: string, message: string, details?: string, status export default { async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise { - // --- Custom KV Rate limiting --- - // --- Rate limiting --- // Use client IP for consistent rate limiting across environments const clientIP = request.headers.get('x-agent') || request.headers.get('cf-connecting-ip'); From 3b511432967937429ded5705b7ca915ee984d846 Mon Sep 17 00:00:00 2001 From: Ankur Datta <64993082+ankur-arch@users.noreply.github.com> Date: Tue, 12 Aug 2025 13:43:20 +0600 Subject: [PATCH 5/5] fix: add logging --- claim-db-worker/src/index.ts | 3 +++ create-db-worker/src/index.ts | 3 +-- package.json | 5 ++++- tests/test-rate-limits.sh | 3 --- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/claim-db-worker/src/index.ts b/claim-db-worker/src/index.ts index a14ddd9..8137a7b 100644 --- a/claim-db-worker/src/index.ts +++ b/claim-db-worker/src/index.ts @@ -36,6 +36,9 @@ export default { const { success } = await env.CLAIM_DB_RATE_LIMITER.limit({ key: clientIP! }); + console.log(`Client IP: ${clientIP} - Request URL: ${request.url}`); + console.log(`Ray ID: ${rayId} - Request Method: ${request.method}`); + if (!success) { console.log(`Rate limit exceeded for IP: ${clientIP}. Ray ID: ${rayId}. Request blocked to prevent abuse.`); return new Response( diff --git a/create-db-worker/src/index.ts b/create-db-worker/src/index.ts index 333115b..ccc09e2 100644 --- a/create-db-worker/src/index.ts +++ b/create-db-worker/src/index.ts @@ -17,6 +17,7 @@ export default { const rayId = request.headers.get('cf-ray') || request.headers.get('x-ray-id') || 'unknown-ray-id'; console.log(`Client IP: ${clientIP} - Request URL: ${request.url}`); + console.log(`Ray ID: ${rayId} - Request Method: ${request.method}`); const { success } = await env.CREATE_DB_RATE_LIMITER.limit({ key: clientIP! }); @@ -27,8 +28,6 @@ export default { error: 'Too Many Requests', message: 'You have exceeded the allowed number of requests. Please wait before trying again.', code: 429, - ip: clientIP, - rayId, }), { status: 429, diff --git a/package.json b/package.json index 8db2339..9001102 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,10 @@ "changeset": "changeset", "version": "changeset version", "publish:cli": "changeset publish --filter create-db", - "prepare": "node .husky/install.mjs" + "prepare": "node .husky/install.mjs", + "deploy-workers": "pnpm run deploy-create-db-worker && pnpm run deploy-claim-worker", + "deploy-claim-worker": "cd claim-db-worker && npx wrangler@latest deploy && cd ..", + "deploy-create-db-worker": "cd create-db-worker && npx wrangler@latest deploy" }, "devDependencies": { "@changesets/cli": "^2.29.5", diff --git a/tests/test-rate-limits.sh b/tests/test-rate-limits.sh index fac2060..cd98ba5 100755 --- a/tests/test-rate-limits.sh +++ b/tests/test-rate-limits.sh @@ -37,9 +37,6 @@ test_worker() { # Make the request with unique agent headers and capture body + status code response=$(curl -s \ - -H "x-agent: $AGENT_ID" \ - -H "x-Agent: $AGENT_ID" \ - -H "User-Agent: prisma-rate-limit-test/$AGENT_ID" \ -w "%{http_code}" \ -o /tmp/response_$i.json \ "$endpoint" 2>/dev/null)