Skip to content

Conversation

@NathanFlurry
Copy link
Member

No description provided.

@vercel
Copy link

vercel bot commented Nov 4, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
rivetkit-serverless Ready Ready Preview Comment Nov 4, 2025 7:26pm
3 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
rivet-cloud Ignored Ignored Nov 4, 2025 7:26pm
rivet-inspector Ignored Ignored Preview Nov 4, 2025 7:26pm
rivet-site Ignored Ignored Preview Nov 4, 2025 7:26pm

This was referenced Nov 4, 2025
Copy link
Member Author

NathanFlurry commented Nov 4, 2025

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more


How to use the Graphite Merge Queue

Add the label merge-queue to this PR to add it to the merge queue.

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@claude
Copy link

claude bot commented Nov 4, 2025

Pull Request Review: Include Method in Cache Key

Overview

This PR fixes a caching issue by including the HTTP method in the cache key generation. This ensures that different HTTP methods (GET, POST, PUT, DELETE, etc.) to the same path produce distinct cache entries.

Positive Aspects ✓

  1. Correct Problem Identification: The PR addresses a real bug where requests with different methods to the same path would incorrectly share cache entries
  2. Consistent Implementation: The change is applied consistently across all call sites (7 locations in proxy_service.rs)
  3. Proper Hashing: Using method.as_str().hash() is the correct approach for including the method in the hash
  4. Good Logging: Added method to debug log output for better observability
  5. Clean Type Signature: The updated CacheKeyFn type signature properly includes &'a hyper::Method with appropriate lifetime bounds

Issues & Recommendations

1. Test Coverage Gap ⚠️

The PR doesn't include any tests verifying this behavior. This is critical since it fixes a bug.

Recommendation: Add a test case that verifies different methods to the same path produce different cache entries. Example test case:

#[tokio::test]
async fn test_cache_key_differentiates_methods() {
    // Make GET and POST requests to same path
    // Verify they produce different cache keys
    // Verify they route independently
}

2. Breaking Change in Test Helper ⚠️

The create_test_cache_key_fn() in guard-core/tests/common/mod.rs:477-492 was updated with the new signature but:

  • Line 481: The method parameter is ignored with _port_type (should be _method)
  • The function doesn't hash the method, creating a mismatch with production behavior

Current code (lines 477-492):

pub fn create_test_cache_key_fn() -> CacheKeyFn {
    Arc::new(
        move |hostname: &str,
              path: &str,
              _port_type: rivet_guard_core::proxy_service::PortType,  // Wrong parameter name
              _headers: &hyper::HeaderMap| {
            // ... doesn't include method in hash
        },
    )
}

Should be:

pub fn create_test_cache_key_fn() -> CacheKeyFn {
    Arc::new(
        move |hostname: &str,
              path: &str,
              method: &hyper::Method,  // Fix parameter name
              _port_type: rivet_guard_core::proxy_service::PortType,
              _headers: &hyper::HeaderMap| {
            let hostname_only = hostname.split(':').next().unwrap_or(hostname);
            let mut hasher = DefaultHasher::new();
            hostname_only.hash(&mut hasher);
            path.hash(&mut hasher);
            method.as_str().hash(&mut hasher);  // Include method
            Ok(hasher.finish())
        },
    )
}

3. Documentation 💡

Consider adding a comment explaining why method is included in the cache key, especially in the CacheKeyFn type definition.

Security Considerations

✓ No security concerns - this change actually improves correctness by preventing method confusion attacks

Performance Considerations

✓ Minimal impact - adding one more field to the hash is negligible
✓ The change may actually improve performance by preventing incorrect cache hits

Code Quality

✓ Follows existing patterns in the codebase
✓ Proper use of structured logging with tracing
✓ Consistent formatting and style

Summary

This is a valuable bug fix that prevents cache key collisions between different HTTP methods. However, it needs:

  1. Test coverage to verify the fix works correctly
  2. Fix the test helper to match production behavior

The core implementation is solid and correctly addresses the issue.


Recommendation: Request changes to add tests and fix the test helper function before merging.

@claude
Copy link

claude bot commented Nov 4, 2025

PR Review: Include Method in Cache Key

Summary

This PR adds the HTTP method to the cache key calculation, which is an important fix to prevent incorrect cache hits between different HTTP methods (GET vs POST, etc.) on the same path.


Code Quality and Correctness ✅

Positive Changes:

  • The implementation correctly threads the method parameter through all necessary layers (proxy_service.rs → cache/mod.rs → cache/actor.rs)
  • Consistent use of method.as_str() for hashing maintains consistency with existing string hashing patterns
  • Good adherence to the logging pattern specified in CLAUDE.md - using structured logging with method = %method
  • All 8 call sites to resolve_route() have been updated to pass the method parameter

Architecture:

  • The change is architecturally sound - including the method in the cache key prevents a real bug where different HTTP methods to the same endpoint could incorrectly share cached routing information
  • The hash calculation order (target → actor_id → path → method) is logical and consistent

Critical Issue Found 🔴

Missing Test Update:
The test helper function create_test_cache_key_fn() in /home/runner/work/rivet/rivet/engine/packages/guard-core/tests/common/mod.rs at line 477-492 has not been updated to match the new function signature.

Current test code (lines 477-492):

pub fn create_test_cache_key_fn() -> CacheKeyFn {
    Arc::new(
        move |hostname: &str,
              path: &str,
              _port_type: rivet_guard_core::proxy_service::PortType,
              _headers: &hyper::HeaderMap| {
            // Missing method parameter!
            let hostname_only = hostname.split(':').next().unwrap_or(hostname);
            
            let mut hasher = DefaultHasher::new();
            hostname_only.hash(&mut hasher);
            path.hash(&mut hasher);
            // Method is NOT being hashed here
            Ok(hasher.finish())
        },
    )
}

The signature is missing the method: &hyper::Method parameter between path and _port_type, and the method is not being hashed. This means:

  1. All tests will fail to compile because the function signature doesn't match the new CacheKeyFn type
  2. Even if they compiled, tests wouldn't be testing the actual behavior since the method wouldn't be included in the cache key

Required Fix:

pub fn create_test_cache_key_fn() -> CacheKeyFn {
    Arc::new(
        move |hostname: &str,
              path: &str,
              method: &hyper::Method,  // Add this parameter
              _port_type: rivet_guard_core::proxy_service::PortType,
              _headers: &hyper::HeaderMap| {
            let hostname_only = hostname.split(':').next().unwrap_or(hostname);
            
            let mut hasher = DefaultHasher::new();
            hostname_only.hash(&mut hasher);
            path.hash(&mut hasher);
            method.as_str().hash(&mut hasher);  // Add this line
            Ok(hasher.finish())
        },
    )
}

Test Coverage ⚠️

Current State:

  • The codebase has comprehensive tests in guard-core/tests/proxy.rs covering rate limiting, max in-flight, timeouts, retries, and different HTTP methods
  • However, there are no specific tests that verify the cache key behavior with different HTTP methods
  • The test_different_http_methods test (lines 459-503) tests that different methods work, but doesn't verify they get different cache keys

Recommendation:
Consider adding a specific test that verifies:

  1. GET and POST requests to the same path get different cache keys
  2. This prevents incorrect cache sharing between methods
  3. The cache key calculation includes all expected components (hostname, path, method)

Performance Considerations ✅

  • Adding one additional hash operation (method.as_str().hash(&mut hasher)) has negligible performance impact
  • The method string is already available and doesn't require allocation
  • Correctly prevents cache pollution, which would cause incorrect routing

Security Considerations ✅

  • This change improves security by preventing cache key collisions between different HTTP methods
  • Without this fix, a GET request could potentially share cached routing with a POST request to the same endpoint, which could lead to:
    • Incorrect routing decisions
    • Middleware configuration mismatches
    • Rate limiting bypass scenarios

Summary

Must Fix:

  • ✅ Update create_test_cache_key_fn() in /home/runner/work/rivet/rivet/engine/packages/guard-core/tests/common/mod.rs to include the method parameter and hash it

Recommendations:

  • ✅ Run cargo test -p rivet-guard-core to verify all tests pass after fixing the test helper
  • ✅ Consider adding a specific test for method-based cache key differentiation

Overall Assessment:
The core implementation is excellent and fixes a real bug. The only blocker is the missing test update, which should be a quick fix. Once that's addressed, this PR is ready to merge.


engine/packages/guard-core/tests/common/mod.rs:477

@claude
Copy link

claude bot commented Nov 4, 2025

PR Review: fix(guard): include method in cache key

Summary

This PR adds HTTP method to the cache key generation for the guard proxy service. This is an important bug fix that prevents incorrect cache hits when the same path is accessed with different HTTP methods (e.g., GET vs POST vs PUT).


✅ Code Quality & Best Practices

Strengths:

  • Consistent implementation: The change is applied uniformly across all resolve_route call sites (7 locations)
  • Type safety: The CacheKeyFn type signature is properly updated to include &hyper::Method
  • Good naming: Function rename from host_path_cache_key to host_path_method_cache_key clearly indicates the added dimension
  • Proper hashing: Method is correctly hashed as a string using method.as_str().hash(&mut hasher) in both actor-specific and fallback cache key functions
  • Logging: Debug log at proxy_service.rs:397 appropriately includes the method in the trace output

Style adherence:

  • ✅ Follows CLAUDE.md conventions for structured logging (e.g., method = %method)
  • ✅ Uses proper error handling patterns with Result types
  • ✅ Comments are updated appropriately (e.g., line 1173: "Capture headers and method before request is consumed")

🐛 Potential Issues

None identified - The implementation is sound and addresses the bug correctly.


⚡ Performance Considerations

Positive:

  • Hash computation is still O(1) with negligible overhead from hashing the additional method string
  • No changes to cache data structures or lookup logic
  • The fix prevents incorrect cache hits, which could have led to subtle bugs and unexpected behavior

Neutral:

  • Cache key space increases slightly (more unique keys due to method differentiation), but this is the correct behavior
  • Memory impact is minimal since method strings are small

🔒 Security Concerns

Positive:

  • This fix prevents a potential security issue where cached responses from one HTTP method could be incorrectly served for requests with a different method
  • Example scenario that's now prevented:
    • User makes GET /api/resource (read operation) → response cached
    • User makes POST /api/resource (write operation) → without this fix, might incorrectly return cached GET response
  • This is especially important for REST APIs where different methods have different semantics and side effects

🧪 Test Coverage

Concern:

  • No tests appear to be added for this critical bug fix
  • Existing test search shows only simple_websocket_test2.rs in the guard packages

Recommendation:
Consider adding a test case that:

  1. Makes a request with one HTTP method (e.g., GET)
  2. Verifies it gets cached
  3. Makes a request to the same path with a different method (e.g., POST)
  4. Verifies it does NOT use the cached response from step 1

Example test structure:

#[tokio::test]
async fn test_cache_key_includes_method() {
    // Setup proxy with mock routing function
    // Send GET request to /test/path
    // Verify response A
    // Send POST request to /test/path  
    // Verify response B (different from A, not cached)
}

📋 Overall Assessment

Rating:Approve with minor recommendation

This is a well-implemented bug fix that addresses a real issue in the caching logic. The change is:

  • ✅ Correct and complete
  • ✅ Consistent across all call sites
  • ✅ Follows project conventions
  • ✅ Has positive security implications
  • ⚠️ Could benefit from test coverage

Recommendation: Merge after considering adding test coverage for method-specific cache keys.


📝 Additional Notes

The refactoring is clean and maintains backward compatibility in terms of the overall architecture. The function signature change is internal to the guard packages and properly propagated throughout the codebase.

@claude
Copy link

claude bot commented Nov 4, 2025

PR Review: fix(guard): include method in cache key

Summary

This PR fixes a critical bug where HTTP requests with different methods (GET, POST, PUT, DELETE, etc.) to the same endpoint were being cached together. The fix properly includes the HTTP method in the cache key calculation.

Code Quality ✅

Positive aspects:

  1. Consistent signature updates - The CacheKeyFn type signature and all call sites have been updated systematically across the codebase
  2. Proper hashing - The method is correctly included in the hash calculation using method.as_str().hash(&mut hasher)
  3. Good logging - Added method to debug logs in proxy_service.rs:397 for better observability
  4. Naming consistency - Updated function names appropriately (e.g., host_path_cache_keyhost_path_method_cache_key)
  5. Clean implementation - The changes are minimal and focused on the specific issue

Potential Issues 🔍

Critical - Cache invalidation:
The most significant concern is cache invalidation. After this change deploys:

  • Old cache entries (without method in key) will have different hash values than new ones
  • This could lead to cache misses for previously cached routes
  • Impact: Temporary increase in routing function calls until old cache entries expire (10 min TTL per proxy_service.rs:44)

Recommendation: Consider whether a cache clear or version bump is needed during deployment.

Code observation:
In proxy_service.rs:1170-1173, the code captures headers and method before the request is consumed:

// Capture headers and method before request is consumed
let req_headers = req.headers().clone();
let req_method = req.method().clone();

The comment is helpful, but clone() on hyper::Method is cheap (it's a small enum), so this is fine.

Test Coverage ⚠️

Missing test coverage:

  1. No tests verify that different HTTP methods to the same endpoint generate different cache keys
  2. No tests validate cache behavior with method inclusion
  3. The existing test helper create_test_cache_key_fn in engine/packages/guard-core/tests/common/mod.rs:477-492 needs to be updated to match the new signature - it's currently missing the method parameter

Current test helper (NEEDS UPDATE):

pub fn create_test_cache_key_fn() -> CacheKeyFn {
    Arc::new(
        move |hostname: &str,
              path: &str,
              _port_type: rivet_guard_core::proxy_service::PortType,
              _headers: &hyper::HeaderMap| {
            // Missing method parameter!
            let hostname_only = hostname.split(':').next().unwrap_or(hostname);
            let mut hasher = DefaultHasher::new();
            hostname_only.hash(&mut hasher);
            path.hash(&mut hasher);
            Ok(hasher.finish())
        },
    )
}

Recommendation:

  1. Update create_test_cache_key_fn to accept and hash the method parameter
  2. Add a test case that verifies GET and POST to the same path produce different cache keys
  3. Add an integration test in engine/packages/guard-core/tests/proxy.rs that verifies requests with different methods don't share cache

Performance Considerations ✅

No concerns:

  • Adding one more field to hash is negligible overhead
  • method.as_str() is essentially free (returns static str reference)
  • Hash function is already being called, so no additional function call overhead

Security Considerations ✅

This is actually a security improvement:

  • Prevents potential security issues where a GET request might serve cached data from a POST/PUT/DELETE
  • Ensures proper HTTP method semantics are respected in caching

Conventions & Style ✅

The code follows the repository's conventions:

  • Uses structured logging with tracing (e.g., tracing::debug!(?err, ...))
  • Proper parameter ordering in function signatures
  • Consistent with existing error handling patterns
  • Follows the hard tabs formatting standard

Action Items

Before merge:

  1. ✅ Fix the test helper create_test_cache_key_fn to match the new signature
  2. 🔄 Consider adding test coverage for method-based cache differentiation
  3. 🔄 Document deployment impact (temporary cache invalidation)

After merge:

  • Monitor routing function call rates during deployment
  • Verify cache hit rates return to normal after TTL expires

Overall assessment: This is a good bug fix that addresses a real caching issue. The implementation is clean and consistent. The main concerns are the missing test updates and potential deployment impact from cache invalidation. The fix itself is sound and improves correctness.

@NathanFlurry NathanFlurry force-pushed the 11-04-fix_guard_include_method_in_cache_key branch from 705c6ca to 28148fb Compare November 4, 2025 20:25
@NathanFlurry NathanFlurry force-pushed the 11-04-chore_engine_move_smoke_test_to_engine_tests_ branch from 30bd99b to 20dd048 Compare November 4, 2025 20:25
@vercel
Copy link

vercel bot commented Nov 4, 2025

Deployment failed with the following error:

Too many requests - try again in 5 minutes (more than 120, code: "api-deployments-flood-pro").

Learn More: https://vercel.com/docs/limits#rate-limits

@claude
Copy link

claude bot commented Nov 4, 2025

PR Review: fix(guard): include method in cache key

Overview

This PR addresses a critical bug where HTTP requests with different methods (GET, POST, PUT, DELETE, etc.) to the same path were sharing cache entries. The fix correctly adds the HTTP method to the cache key calculation across all relevant code paths.


✅ Strengths

  1. Correct Problem Identification: This fixes a real bug that could lead to incorrect request routing and cache pollution
  2. Consistent Implementation: The method parameter is properly threaded through all 7 call sites in proxy_service.rs
  3. Type Safety: The CacheKeyFn type signature is correctly updated with proper lifetime bounds
  4. Good Logging: Added method to debug output at proxy_service.rs:397 for better observability
  5. Proper Hashing: Uses method.as_str().hash() consistently in both the actor-specific and fallback cache key functions
  6. Naming Consistency: Function renamed from host_path_cache_key to host_path_method_cache_key to reflect the change

🐛 Critical Issue Found

Test Helper Function Missing Hash Implementation

In engine/packages/guard-core/tests/common/mod.rs:477-492, the test helper function create_test_cache_key_fn() was updated with the correct signature (including the _method parameter on line 481), but the method is not being hashed on lines 487-490.

Current code:

let mut hasher = DefaultHasher::new();
hostname_only.hash(&mut hasher);
path.hash(&mut hasher);
// method is NOT being hashed here!
Ok(hasher.finish())

This creates a discrepancy between production and test behavior:

  • Production code (in engine/packages/guard/src/cache/mod.rs:60-69): ✅ Hashes hostname, path, AND method
  • Test code: ❌ Only hashes hostname and path

Impact:

  • Tests won't verify the actual fix
  • Different cache key values between production and test environments
  • False confidence that tests are validating the correct behavior

Required Fix:

let mut hasher = DefaultHasher::new();
hostname_only.hash(&mut hasher);
path.hash(&mut hasher);
method.as_str().hash(&mut hasher);  // Add this line
Ok(hasher.finish())

Also update the parameter name from _method to method since it's now being used.


📋 Test Coverage Gap

While the codebase has extensive integration tests (proxy, websocket, rate limiting, etc.), there are no specific tests that verify cache key differentiation by HTTP method.

Recommendation: Consider adding a test that explicitly verifies:

  1. Two requests to the same path with different methods produce different cache keys
  2. The cache entries are independent (not shared between methods)

🔒 Security Impact

Positive: This change prevents a security issue where:

  • A cached response from GET /api/resource could incorrectly be returned for POST /api/resource
  • Different HTTP methods have different semantics (read vs write operations) and should never share cache entries
  • Middleware configurations (rate limits, timeouts) are now correctly isolated per method

⚡ Performance Impact

Neutral/Positive:

  • Adding one hash operation has negligible performance impact
  • Prevents incorrect cache hits that could cause routing errors
  • May slightly increase cache memory usage (more unique keys), but this is the correct behavior

📝 Code Style

✅ Follows CLAUDE.md conventions:

  • Structured logging with tracing::debug!(?x, "message") pattern
  • Proper error handling with Result types
  • Consistent use of workspace dependencies

Overall Assessment

Rating: ⚠️ Requires Changes

This is an excellent bug fix with correct implementation in production code. However, the test helper function must be updated to match production behavior before merging.

Action Items:

  1. 🔴 Blocker: Fix create_test_cache_key_fn() in engine/packages/guard-core/tests/common/mod.rs:489 to include method in hash
  2. 🟡 Recommended: Add explicit test case for method-based cache differentiation
  3. 🟢 Optional: Run cargo test -p rivet-guard-core to verify all tests pass after the fix

Once the test helper is fixed, this PR will be ready to merge. The core implementation is solid and addresses an important correctness issue in the caching layer.


Files Reviewed:

  • engine/packages/guard-core/src/proxy_service.rs
  • engine/packages/guard/src/cache/mod.rs
  • engine/packages/guard/src/cache/actor.rs
  • engine/packages/guard-core/tests/common/mod.rs ⚠️

@graphite-app
Copy link
Contributor

graphite-app bot commented Nov 4, 2025

Merge activity

  • Nov 4, 8:53 PM UTC: NathanFlurry added this pull request to the Graphite merge queue.
  • Nov 4, 8:53 PM UTC: CI is running for this pull request on a draft pull request (#3353) due to your merge queue CI optimization settings.
  • Nov 4, 8:56 PM UTC: Merged by the Graphite merge queue via draft PR: #3353.

graphite-app bot pushed a commit that referenced this pull request Nov 4, 2025
@graphite-app graphite-app bot closed this Nov 4, 2025
@graphite-app graphite-app bot deleted the 11-04-fix_guard_include_method_in_cache_key branch November 4, 2025 20:56
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.

3 participants