Skip to content

fix(ops): db-aware health check + rate limit on paid API fan-out views - #379

Merged
paruff merged 1 commit into
mainfrom
fix/health-check-and-rate-limiting
Aug 21, 2026
Merged

fix(ops): db-aware health check + rate limit on paid API fan-out views#379
paruff merged 1 commit into
mainfrom
fix/health-check-and-rate-limiting

Conversation

@paruff

@paruff paruff commented Aug 21, 2026

Copy link
Copy Markdown
Owner

Summary

Two of the high-value fixes from the production-readiness audit:

  • /health/ didn't verify anything — Render's healthCheckPath gates deploys on this endpoint, but it returned a static {"status": "ok"} unconditionally. A DB-down instance would still pass the deploy gate. It now runs SELECT 1 and returns 503 if the database is unreachable.
  • No rate limiting on views that fan out to paid third-party APIsscreen_property() can call Rentometer/HUD FMR/ATTOM per property. screening_preview, pipeline_screener's rescreen action, and pipeline_screening_settings' post-save rescreen all iterate a user's entire pipeline with no cap on how often that can be triggered. Added core/decorators.py (rate_limit/is_rate_limited, built on django.core.cache — no new dependency) and applied it to all three.

(The third audit item — rollback documentation — turned out to already exist in docs/how-to-guides/render-deploy.md; no action needed there.)

Changes

  • core/decorators.py (new) — rate_limit/is_rate_limited
  • core/views/__init__.py — DB check in health_check; rate limiting on the three fan-out views
  • conftest.py — autouse fixture clearing Django's cache between tests (found this was needed when a pre-existing test failed only when run after other tests hitting the same view — the cache is process-global)
  • tests/test_rentometer.py — removed its now-redundant local cache-clearing fixture (superseded by the conftest one)
  • core/tests/test_decorators.py, core/tests/test_views.py — new tests

Test plan

  • New tests: DB-unreachable health check returns 503; rate limiter allows-under/blocks-over-limit, is per-user, and the decorator form returns 429
  • ruff check/ruff format --check/mypy clean
  • manage.py check — no issues
  • Full suite: 2006 passed, 1 skipped, 0 failures

🤖 Generated with Claude Code

From the production-readiness audit:

- /health/ (Render's healthCheckPath) returned a static {"status": "ok"}
  with no dependency check. A DB-down instance would still pass Render's
  deploy gate. Now runs SELECT 1 and returns 503 if the DB is unreachable.

- No app-level rate limiting existed on views that fan out to paid,
  metered third-party APIs (Rentometer, HUD FMR, ATTOM) via
  screen_property() — a user re-screening a large pipeline, or repeating
  screening_preview POSTs, had no cap on outbound calls. Added
  core/decorators.py (rate_limit / is_rate_limited, built on
  django.core.cache — no new dependency) and applied it to the three
  views that trigger this fan-out: screening_preview (10/5min),
  pipeline_screener's rescreen action (5/5min), and
  pipeline_screening_settings' post-save rescreen (5/5min — criteria are
  still saved even if the rescreen itself is rate-limited).

Also added an autouse cache-clearing fixture to the root conftest.py:
Django's cache is process-global, and without clearing it between tests,
rate-limit state (and Rentometer's own cache) leaks across test runs —
found this the hard way when a pre-existing screening-settings test
failed only when run after other tests that hit the same view.

Full suite: 2006 passed, 0 failures.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Comment thread core/views/__init__.py
request,
"Too many re-screens — please wait a few minutes and try again.",
)
return redirect(request.get_full_path())
@paruff paruff changed the title fix(ops): DB-aware health check + rate limit on paid API fan-out views fix(ops): db-aware health check + rate limit on paid API fan-out views Aug 21, 2026
@paruff
paruff merged commit bf2b802 into main Aug 21, 2026
52 of 58 checks passed
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.

2 participants