Skip to content

Rate limiter on paid-API fan-out views only enforces ~2x the configured cap under production process topology #396

Description

@paruff

Summary

Found during a retrospective code review of merged PR #379 (fix(ops): db-aware health check + rate limit on paid API fan-out views). The new rate limiter is correctly wired (keys on request.user.pk, all guarded views are @login_required so it's not bypassable via spoofable headers) but its actual cap is weaker than documented under the production deployment topology, undercutting the PR's stated goal of bounding paid third-party API cost/DoS exposure.

Root cause

File: core/decorators.py:18-20 (_increment, uses django.core.cache.cache)

No CACHES setting exists anywhere in investor_app/settings.py (confirmed via repo-wide grep), so Django defaults to LocMemCache, which is local to each process. render.yaml runs gunicorn with --workers 2, so each worker process tracks its own independent in-memory counter for the same user. A limit stated as "5 rescreens per 5 minutes" is therefore enforceable only up to ~10 per 5 minutes in the worst case (requests happen to land on both workers), directly undercutting the intent.

This isn't caught by the existing tests (core/tests/test_decorators.py) because they all run single-process via RequestFactory and can't surface a multi-worker cache-partitioning issue.

Fix

Back the cache with a shared store (e.g. Redis via django-redis) in production settings so the counter is consistent across gunicorn workers, or explicitly document the reduced guarantee if a shared cache isn't feasible right now.

Related, lower-priority follow-up (not a bug in this PR, worth tracking separately if pipeline sizes grow)

The rate limit bounds trigger frequency, not total downstream fan-out per trigger. pipeline_screener's rescreen branch and pipeline_screening_settings's rescreen loop each still call screen_property() once per property in the (unfiltered) pipeline, which hits Rentometer/HUD/ATTOM per property when rent-based criteria apply. A user with a large pipeline can still trigger limit × pipeline_size paid API calls within the rate-limit window (e.g. 5 triggers × 500 properties = 2,500 calls in 5 minutes).

Full review: .claude/reviews/pr-379-review.md

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1:dataPhase 1: Fix the Data ProblembugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions