Skip to content

Improve rate limits and caching for shared-IP environments#10096

Draft
santicomp2014 wants to merge 1 commit intomainfrom
feature/rate-limit-improvements
Draft

Improve rate limits and caching for shared-IP environments#10096
santicomp2014 wants to merge 1 commit intomainfrom
feature/rate-limit-improvements

Conversation

@santicomp2014
Copy link
Copy Markdown
Contributor

Summary

  • Bump rate limits: General API 4r/s→10r/s, burst 44→200. Badge 1r/s→10r/s, burst 15→100.
  • Add cache headers: Cache-Control: public, max-age=60 on unauthenticated search responses and all badge responses. Identical queries from shared-IP users (conference WiFi, university networks) are now served from CloudFlare/browser cache.
  • Enable nginx access logging: JSON structured logs to stdout with status codes and CF-Connecting-IP for rate limit visibility (previously access_log off).
  • Includes analysis doc: docs/rate-limiting-solutions.md with full problem analysis, Bio's actual request patterns, and phased solution roadmap.

Context

Partners like bioRxiv/medRxiv make multiple unauthenticated search API calls per page load (2 groups × paginated at limit=50). In shared-IP environments, all users share one rate limit bucket based on CF-Connecting-IP. A heavily-annotated article (500 annotations) at a 200-person conference = ~4,000 requests from one IP, causing widespread 429s.

The cache headers are the highest-leverage fix: all 4,000 requests collapse to ~20 unique queries per minute since every user makes identical paginated calls for the same article.

Ref: product-backlog#1716

Test plan

  • Verify unauthenticated /api/search responses include Cache-Control: public, max-age=60
  • Verify authenticated /api/search responses do NOT include cache headers
  • Verify /api/badge responses include Cache-Control: public, max-age=60 for non-blocked URIs
  • Verify blocked URI badge responses still get 1-day cache
  • Verify nginx access logs are output as JSON to stdout
  • Load test: confirm higher burst limits handle shared-IP traffic without 429s
  • Unit tests pass for new cache header behavior

🤖 Generated with Claude Code

Partners like bioRxiv/medRxiv make multiple unauthenticated search API
calls per page load (2 groups x paginated at limit=50). In shared-IP
environments (conferences, universities), all users share one rate
limit bucket, causing 429s.

Changes:
- Bump general API rate limit from 4r/s burst=44 to 10r/s burst=200
- Bump badge rate limit from 1r/s burst=15 to 10r/s burst=100
- Add Cache-Control: public, max-age=60 on unauthenticated search
  responses and all badge responses (identical queries from shared-IP
  users now served from CloudFlare/browser cache)
- Enable nginx JSON access logging for rate limit visibility
- Increase rate limit zone memory from 1m to 2m (~16k users)

Ref: product-backlog#1716

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@santicomp2014 santicomp2014 self-assigned this Apr 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant