Skip to content

Introduce cache mechanism support#160

Merged
touale merged 3 commits into
masterfrom
feat/support-cache
May 16, 2026
Merged

Introduce cache mechanism support#160
touale merged 3 commits into
masterfrom
feat/support-cache

Conversation

@touale
Copy link
Copy Markdown
Owner

@touale touale commented May 16, 2026

Summary by CodeRabbit

  • New Features

    • Added configurable request caching with support for in-memory and file-based storage modes.
    • New cache control HTTP headers for managing cache behavior per request.
    • Cache status reporting indicating hit/miss/bypass/refresh outcomes.
    • Configuration options for cache TTL, maximum size, and storage mode selection.
  • Tests

    • Added comprehensive test coverage for cache functionality across storage modes and request control scenarios.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 16, 2026

Warning

Rate limit exceeded

@touale has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 48 minutes and 10 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 97a2ab5f-744a-49df-9c47-fbe3048e62a9

📥 Commits

Reviewing files that changed from the base of the PR and between 3081c3b and 992ff9b.

📒 Files selected for processing (2)
  • src/framex/driver/cache.py
  • tests/driver/test_request_cache.py

Walkthrough

This PR introduces a complete request-scoped HTTP response caching system for FrameX with in-memory and file-based storage backends, configuration validation, request-header-based cache control (USE/BYPASS/REFRESH), and integration into route handlers and decorators.

Changes

Request-level HTTP response caching

Layer / File(s) Summary
Cache configuration and constants
src/framex/config.py, src/framex/consts.py, tests/test_config.py
CacheConfig model defines enablement, storage mode, TTL, max size, and file directory; Settings extended to include cache config. New constants: cache HTTP header names, supported methods, and CacheAction/CacheStatus StrEnum types. Config tests validate defaults and reject invalid mode/TTL/max_size.
RequestCache driver core
src/framex/driver/cache.py
Main caching driver with request-scoped call() method. Dual backends: in-memory (aiocache) with TTL and max-size eviction, and file-based (JSON) with metadata tracking. Deterministic cache-key generation via optional key_builder callback. TTL validation, cache action resolution from headers (USE/BYPASS/REFRESH), and JSON serialization with error fallback to bypass.
Ingress route and decorator integration
src/framex/driver/ingress.py, src/framex/plugin/on.py, tests/test_plugin.py
APIIngress.register_route() gains optional cache parameter and routes calls through request_cache.call() when enabled. @on_request decorator accepts and normalizes cache config before route registration. Route handler gains request parameter to support caching. Decorator tests validate config preservation and validation.
RequestCache integration tests
tests/driver/test_request_cache.py
Async tests cover: disabled-cache bypass behavior, in-memory hit/miss patterns, header-driven bypass/refresh control, custom key builders with context, file-based persistence and on-disk editing, and FIFO eviction at max size. Uses fixture to configure cache settings and clear state between tests.

Sequence Diagram

sequenceDiagram
  participant Client
  participant RouteHandler
  participant RequestCache
  participant MemoryStore
  participant Adapter
  Client->>RouteHandler: GET /api/data?x=1
  RouteHandler->>RouteHandler: check cache enabled
  RouteHandler->>RequestCache: call(request, invoke)
  RequestCache->>RequestCache: parse X-FrameX-Cache header
  RequestCache->>RequestCache: build cache key
  RequestCache->>MemoryStore: get(hashed_key)
  alt First request (MISS)
    MemoryStore-->>RequestCache: null
    RequestCache->>Adapter: invoke()
    Adapter-->>RequestCache: {data: value}
    RequestCache->>MemoryStore: set(hashed_key, {data: value})
    RequestCache->>RouteHandler: {data: value} + X-FrameX-Cache-Status: MISS
  else Subsequent request (HIT)
    MemoryStore-->>RequestCache: {data: value}
    RequestCache->>RouteHandler: {data: value} + X-FrameX-Cache-Status: HIT
  end
  RouteHandler->>Client: response + cache headers
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • touale/FrameX-kit#81: Modifies APIIngress.register_route() signature and route handler wiring for the /version endpoint.
  • touale/FrameX-kit#102: Updates APIIngress.register_route() and route_handler request handling patterns.
  • touale/FrameX-kit#31: Modifies route registration and handler wiring to add auth-key dependency injection.

Poem

🐰 A cache layer hops into the frame,
In memory or files, the logic stays the same.
Headers steer BYPASS, REFRESH, and USE,
Your responses now bounce back—no more waiting for news! 🚀

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main objective of the PR: introducing cache mechanism support across configuration, constants, drivers, and tests.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/support-cache

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@codecov
Copy link
Copy Markdown

codecov Bot commented May 16, 2026

Codecov Report

❌ Patch coverage is 78.51562% with 55 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/framex/driver/cache.py 77.37% 37 Missing and 13 partials ⚠️
src/framex/driver/ingress.py 54.54% 4 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown

@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: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/framex/driver/cache.py`:
- Around line 295-296: In _stable_value, the current branch treats
list/tuple/set the same, but iterating a set is non-deterministic; update the
set handling in the _stable_value function so that when value is a set you first
convert each item via _stable_value, then sort the resulting items
deterministically (for example by their string/JSON representation or a stable
key) and return that sorted list so equivalent sets produce the same cache key.
- Around line 89-120: When _cache_action(request) returns CacheAction.BYPASS you
must skip both cache reads and cache writes: detect CacheAction.BYPASS (in
addition to the existing CacheAction.USE branch), call and return await invoke()
immediately, set response.headers[CACHE_STATUS_HEADER] = CacheStatus.BYPASS, and
do not call self.set or create CacheEntryMetadata for that request; keep
existing behavior for CacheAction.USE (attempt get) and CacheAction.REFRESH
(allow write/refresh).

In `@tests/driver/test_request_cache.py`:
- Around line 175-177: In the test's custom key-builder (function build_key)
you're appending a dict-keys view to seen_keys which causes equality checks to
fail; change the capture to a concrete list by replacing
seen_keys.append(context.keys()) with seen_keys.append(list(context.keys()))
(and make the same list(...) conversion for any other places that append or
record context.keys() so the later assertions that compare against concrete
lists (related to seen_keys) will succeed); refer to build_key and seen_keys
when making the change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a59dcfa7-82c8-4e6d-9055-b70213fc27fd

📥 Commits

Reviewing files that changed from the base of the PR and between 9aaaaaf and 3081c3b.

📒 Files selected for processing (8)
  • src/framex/config.py
  • src/framex/consts.py
  • src/framex/driver/cache.py
  • src/framex/driver/ingress.py
  • src/framex/plugin/on.py
  • tests/driver/test_request_cache.py
  • tests/test_config.py
  • tests/test_plugin.py

Comment thread src/framex/driver/cache.py
Comment thread src/framex/driver/cache.py Outdated
Comment on lines +175 to +177
def build_key(request: Request, context: Any) -> str:
seen_keys.append(context.keys())
return request.url.path
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fix key list capture type in custom key-builder test

Line 176 appends a keys-view, but Line 202 asserts concrete lists; this can fail the assertion despite correct cache behavior.

Proposed fix
 def build_key(request: Request, context: Any) -> str:
-    seen_keys.append(context.keys())
+    seen_keys.append(list(context.keys()))
     return request.url.path

Also applies to: 202-203

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/driver/test_request_cache.py` around lines 175 - 177, In the test's
custom key-builder (function build_key) you're appending a dict-keys view to
seen_keys which causes equality checks to fail; change the capture to a concrete
list by replacing seen_keys.append(context.keys()) with
seen_keys.append(list(context.keys())) (and make the same list(...) conversion
for any other places that append or record context.keys() so the later
assertions that compare against concrete lists (related to seen_keys) will
succeed); refer to build_key and seen_keys when making the change.

@touale touale merged commit c1754dd into master May 16, 2026
10 of 11 checks passed
@touale touale deleted the feat/support-cache branch May 16, 2026 12:05
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