Skip to content

Cache API settings helper#23

Merged
shayancoin merged 3 commits intomainfrom
codex/add-lru_cache-for-get_settings-helper
Oct 15, 2025
Merged

Cache API settings helper#23
shayancoin merged 3 commits intomainfrom
codex/add-lru_cache-for-get_settings-helper

Conversation

@shayancoin
Copy link
Owner

@shayancoin shayancoin commented Oct 15, 2025

Summary

  • add an lru_cache-backed get_settings helper to reuse a single Settings instance
  • update FastAPI modules to import the helper instead of instantiating new settings objects

Testing

  • not run (not requested)

https://chatgpt.com/codex/tasks/task_e_68ef016c3b548330ac27ebb75ca35df9

Summary by CodeRabbit

  • Refactor

    • Centralized and cached application settings to provide consistent configuration access and lower runtime overhead.
  • Chores

    • Switched initialization and service setup to use the centralized settings provider, resulting in more stable startup behavior and a single source of truth for environment-driven settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 15, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Adds a cached settings factory get_settings() (with @lru_cache) in backend/api/config.py, updates imports in backend/api/db.py, backend/api/main.py, and backend/api/routes_sync.py to use get_settings(). routes_sync.py now pre-instantiates a module-level HygraphService. db.py import change may mismap to remaining Settings() usage.

Changes

Cohort / File(s) Summary
Config caching function
backend/api/config.py
Adds get_settings() -> Settings decorated with @lru_cache() and imports lru_cache from functools to expose a cached Settings factory.
App initialization
backend/api/main.py
Replaces from api.config import Settings with from api.config import get_settings and changes settings = Settings()settings = get_settings().
DB config import
backend/api/db.py
Replaces import Settingsget_settings from api.config; remaining usage still references Settings() (potential mismatch to review).
Hygraph service singleton
backend/api/routes_sync.py
Switches to get_settings() import; creates module-level settings = get_settings() and _hygraph_service = HygraphService(settings.hygraph_token), get_hygraph_service() returns the pre-instantiated singleton.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant App as FastAPI App
    participant Config as config.get_settings
    participant S as Settings (cached)
    participant DB as db.get_engine_url
    participant Route as routes_sync.get_hygraph_service
    participant H as HygraphService

    App->>Config: get_settings()
    note right of Config #D1F2E8: @lru_cache returns cached instance
    Config-->>App: S

    DB->>Config: get_settings()
    Config-->>DB: S
    DB->>DB: Resolve DB URL (may still reference Settings())

    Route->>Config: get_settings() (module init)
    Config-->>Route: S
    Route->>H: Init _hygraph_service with S.hygraph_token
    Route-->>Route: get_hygraph_service() returns _hygraph_service
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • Cache API settings helper #23 — Adds the same @lru_cache get_settings() and updates imports/usages across backend/api/{db.py,main.py,routes_sync.py} (strong overlap).

Poem

I cached a carrot, snug and neat,
One hop to fetch it — no repeat.
Settings held in one small warren,
Routes and app now lightly borrow.
A rabbit’s cheer for faster feet. 🥕🐇

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The pull request description does not follow the repository template: it replaces the required '# PR Type', '# Short Description', and '# Tests Added' sections with custom '## Summary' and '## Testing' headings and omits the PR Type field entirely, preventing clear identification of the change category and test coverage. Additionally, the 'Testing' section does not align with the expected 'Tests Added' section format and lacks details on test cases. Please revise the description to align with the repository template by adding a '# PR Type' section (e.g., 'Feature'), a '# Short Description', and a '# Tests Added' section that details any new or existing tests. Replace the custom headings with the exact template headings and ensure the test coverage is clearly documented.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title succinctly summarizes the primary change of adding a cached settings helper for the API and clearly reflects the main enhancement without unnecessary detail.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2d7f27a and c9efcdd.

📒 Files selected for processing (3)
  • backend/api/db.py (1 hunks)
  • backend/api/main.py (2 hunks)
  • backend/api/routes_sync.py (2 hunks)

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
backend/api/routes_sync.py (1)

33-33: Fix line length to comply with linting rules.

Line 33 exceeds the 88-character limit (93 characters). Split the condition or use an intermediate variable.

-        if not x_hygraph_signature or not service.verify_signature(raw, x_hygraph_signature):
+        signature_valid = (
+            x_hygraph_signature and service.verify_signature(raw, x_hygraph_signature)
+        )
+        if not signature_valid:
             raise HTTPException(status_code=401, detail="invalid signature")
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 102fc53 and 403826d.

📒 Files selected for processing (4)
  • backend/api/config.py (2 hunks)
  • backend/api/db.py (2 hunks)
  • backend/api/main.py (2 hunks)
  • backend/api/routes_sync.py (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
backend/api/routes_sync.py (2)
backend/api/config.py (1)
  • get_settings (50-53)
backend/services/hygraph_service.py (2)
  • HygraphService (11-44)
  • __init__ (12-15)
backend/api/db.py (2)
backend/api/config.py (1)
  • get_settings (50-53)
backend/alembic/env.py (1)
  • get_url (27-31)
backend/api/main.py (1)
backend/api/config.py (1)
  • get_settings (50-53)
🪛 GitHub Actions: CI
backend/api/routes_sync.py

[error] 32-32: E501 Line too long (93 > 88) for signature verification logic.

🔇 Additional comments (7)
backend/api/config.py (1)

3-3: LGTM!

Adding lru_cache import is appropriate for implementing a cached settings singleton.

backend/api/db.py (2)

11-11: LGTM!

Import correctly updated to use the cached settings factory.


35-35: All direct Settings() instantiations have been replaced
Search returned only docstrings in backend/api/config.py; no remaining Settings() calls outside the cached factory.

backend/api/routes_sync.py (2)

10-10: LGTM!

Import correctly updated to use the cached settings factory.


19-19: LGTM!

Correctly uses the cached settings factory to retrieve configuration.

backend/api/main.py (2)

9-9: LGTM!

Import correctly updated to use the cached settings factory.


24-24: LGTM!

The module-level initialization correctly uses the cached settings factory. This ensures a single Settings instance is shared across the application, which is the intended behavior of this PR.

Comment on lines +49 to +53
@lru_cache()
def get_settings() -> Settings:
"""Return a cached instance of :class:`Settings`."""

return Settings()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider making the cache size explicit.

The implementation is correct, but since get_settings() takes no parameters, only one instance will ever be cached. Consider using @lru_cache (no parentheses) or @lru_cache(maxsize=1) to make the singleton intent clearer.

-@lru_cache()
+@lru_cache
 def get_settings() -> Settings:
     """Return a cached instance of :class:`Settings`."""
-
     return Settings()

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In backend/api/config.py around lines 49 to 53 the decorator uses @lru_cache()
which creates a cache with the default maxsize (128) even though get_settings()
has no parameters; change the decorator to either @lru_cache (no parentheses) or
@lru_cache(maxsize=1) so the singleton intent is explicit and only one Settings
instance is ever cached.

@shayancoin
Copy link
Owner Author

This branch has conflicts that must be resolved
Use the web editor or the command line to resolve conflicts before continuing.

backend/api/db.py
backend/api/routes_sync.py

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 403826d and 2d7f27a.

📒 Files selected for processing (1)
  • backend/api/routes_sync.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
backend/api/routes_sync.py (1)
backend/api/config.py (1)
  • get_settings (50-53)
🔇 Additional comments (2)
backend/api/routes_sync.py (2)

10-10: LGTM: Import change aligns with settings helper pattern.

The switch from importing Settings directly to using get_settings() is appropriate for centralizing settings instantiation.


22-25: LGTM: Function correctly returns the singleton instance.

The refactored function appropriately returns the pre-instantiated service and includes a clear docstring. The Depends() integration on the endpoint remains compatible, though the dependency injection benefit is reduced with a singleton.

Comment on lines +17 to +19
# Using hygraph_token as webhook secret in MVP; adjust if separate secret provided
settings = get_settings()
_hygraph_service = HygraphService(webhook_secret=settings.hygraph_token)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Verify initialization safety and confirm lru_cache decorator.

Module-level initialization creates several concerns:

  1. Import-time failure risk: If get_settings() or HygraphService initialization fails (e.g., missing env vars, invalid token), the entire module import fails rather than failing gracefully at request time.

  2. Testability degradation: The singleton is created once at import, making it harder to:

    • Mock the service in tests
    • Reset state between test cases
    • Test with different configurations
  3. Missing cache decorator: The relevant code snippet shows get_settings() without an @lru_cache decorator, which contradicts the PR description stating "lru_cache-backed get_settings helper." This means Settings() is instantiated on every call to get_settings(), negating the caching benefit at this layer.

Run the following script to verify the lru_cache decorator and search for potential test files that might be affected:


🏁 Script executed:

#!/bin/bash
# Verify lru_cache decorator and find test files

echo "=== Checking get_settings implementation for lru_cache decorator ==="
rg -A 3 -B 1 'def get_settings' backend/api/config.py

echo -e "\n=== Finding test files that might mock or use HygraphService ==="
fd -e py test backend/tests --exec rg -l 'HygraphService|routes_sync'

echo -e "\n=== Checking for existing test patterns around settings ==="
rg -n 'Settings|get_settings' backend/tests/ --type py -C 2 2>/dev/null || echo "No tests directory found or no matches"

Length of output: 359


Lazy-initialize HygraphService instead of module-level instantiation
Avoid calling get_settings() and creating _hygraph_service at import time (backend/api/routes_sync.py:17–19). Import-time init can crash the app on missing/invalid env vars and makes tests hard to mock or reset. Move this into a factory or a get_hygraph_service() function (with internal caching) so it fails gracefully at runtime and is mockable in tests.

🤖 Prompt for AI Agents
In backend/api/routes_sync.py around lines 17 to 19, avoid calling
get_settings() and instantiating HygraphService at import time; instead create a
get_hygraph_service() factory that lazy-initializes and caches a module-level
_hygraph_service on first call (calling get_settings() there), so creation
happens at runtime, failures surface gracefully, and tests can monkeypatch or
reset the cached instance; ensure the factory returns the cached instance on
subsequent calls and provide a simple way to reset or replace the cached service
in tests if needed.

@shayancoin shayancoin merged commit ba0fdae into main Oct 15, 2025
1 of 6 checks passed
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 15, 2025

Note

Docstrings generation - SUCCESS
Generated docstrings for this pull request at #38

coderabbitai bot added a commit that referenced this pull request Oct 15, 2025
Docstrings generation was requested by @shayancoin.

* #23 (comment)

The following files were modified:

* `backend/api/config.py`
* `backend/api/routes_sync.py`
shayancoin pushed a commit that referenced this pull request Oct 16, 2025
Docstrings generation was requested by @shayancoin.

* #23 (comment)

The following files were modified:

* `backend/api/config.py`
* `backend/api/routes_sync.py`

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
shayancoin added a commit that referenced this pull request Oct 16, 2025
* Cache API settings helper

* Reuse cached Hygraph service

* 📝 Add docstrings to `codex/add-lru_cache-for-get_settings-helper` (#38)

Docstrings generation was requested by @shayancoin.

* #23 (comment)

The following files were modified:

* `backend/api/config.py`
* `backend/api/routes_sync.py`

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant