Skip to content

fix: wrap cache purge operations in try-catch for graceful degradation#857

Closed
abnegate wants to merge 1 commit intomainfrom
fix/graceful-cache-purge
Closed

fix: wrap cache purge operations in try-catch for graceful degradation#857
abnegate wants to merge 1 commit intomainfrom
fix/graceful-cache-purge

Conversation

@abnegate
Copy link
Copy Markdown
Member

@abnegate abnegate commented Apr 17, 2026

Summary

  • Wrap purgeCachedCollection() and purgeCachedDocumentInternal() in try-catch blocks
  • Log warning messages instead of throwing exceptions when cache purge fails
  • Match existing pattern used for cache load and save operations

Context

During a production incident, cache failures on purge operations propagated as exceptions, causing HTTP request failures. This change ensures cache infrastructure issues don't cascade to application failures.

Test plan

  • Existing unit tests pass
  • Cache purge failures now log warnings instead of throwing
  • HTTP requests complete successfully even when cache is unavailable

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • Bug Fixes
    • Enhanced cache invalidation stability with improved error handling to prevent operation failures from impacting system reliability.

Cache purge failures should not propagate exceptions up the stack and cause
HTTP request failures. This matches the existing pattern for cache load and
save operations which already use try-catch with warning logging.

When cache is slow or unavailable, purge operations now:
- Log a warning message instead of throwing
- Allow the request to continue successfully
- Prevent cascading failures during cache infrastructure issues

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 17, 2026

📝 Walkthrough

Walkthrough

The Database class now wraps cache purging operations in try/catch blocks, suppressing exceptions and emitting warnings instead of propagating failures during cache invalidation. Both purgeCachedCollection() and purgeCachedDocumentInternal() maintain unconditional true returns.

Changes

Cohort / File(s) Summary
Cache Error Handling
src/Database/Database.php
Wrapped cache listing and purging operations in try/catch blocks to gracefully handle exceptions, emitting warnings instead of propagating failures.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~5 minutes

Possibly related PRs

  • utopia-php/database#758: Also modifies cache purge failure handling in purgeCachedCollection() and purgeCachedDocumentInternal(), but implements retry/rollback logic and converts purgeCachedDocument to a protected method.

Suggested reviewers

  • fogelito

Poem

🐰 Hoppy whiskers twitch with glee,
Cache purges now won't make us flee!
Errors wrapped in try and catch,
Warnings glow, a perfect match
Resilience hops through every line!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: wrapping cache purge operations in try-catch blocks for graceful error handling. It accurately summarizes the primary modification in the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/graceful-cache-purge

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.

@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Apr 17, 2026

Greptile Summary

Wraps purgeCachedCollection() and purgeCachedDocumentInternal() in try-catch blocks so cache purge failures log a warning via Console::warning instead of propagating as exceptions. The implementation correctly follows the existing pattern already in place for cache load and save operations.

Confidence Score: 5/5

Safe to merge — minimal, focused change with no logic risk.

Both new catch blocks are consistent with the established pattern for cache load/save. No P0/P1 issues; the only finding is a stale @throws docblock.

No files require special attention.

Important Files Changed

Filename Overview
src/Database/Database.php Both purgeCachedCollection and purgeCachedDocumentInternal now wrap cache operations in try-catch, logging warnings on failure. Pattern is consistent with existing cache load/save handling. Minor: @throws Exception docblock on purgeCachedDocumentInternal is now stale.

Comments Outside Diff (1)

  1. src/Database/Database.php, line 8238 (link)

    P2 Stale @throws Exception docblock

    purgeCachedDocumentInternal now swallows every Exception internally, so the @throws Exception annotation on line 8238 is no longer accurate and may mislead callers.

Reviews (1): Last reviewed commit: "fix: wrap cache purge operations in try-..." | Re-trigger Greptile

Copy link
Copy Markdown
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.

🧹 Nitpick comments (1)
src/Database/Database.php (1)

8217-8226: Best-effort purge currently aborts on first failure.

At Line 8219-Line 8223, one thrown exception stops the rest of the purge path, so remaining keys may stay stale. Splitting try/catch blocks per operation keeps graceful degradation while maximizing invalidation coverage.

♻️ Suggested refactor
-        try {
-            $documentKeys = $this->cache->list($collectionKey);
-            foreach ($documentKeys as $documentKey) {
-                $this->cache->purge($documentKey);
-            }
-
-            $this->cache->purge($collectionKey);
-        } catch (Exception $e) {
-            Console::warning('Failed to purge collection from cache: ' . $e->getMessage());
-        }
+        try {
+            $documentKeys = $this->cache->list($collectionKey);
+        } catch (Exception $e) {
+            Console::warning('Failed to list collection cache keys: ' . $e->getMessage());
+            $documentKeys = [];
+        }
+
+        foreach ($documentKeys as $documentKey) {
+            try {
+                $this->cache->purge($documentKey);
+            } catch (Exception $e) {
+                Console::warning('Failed to purge cached document key: ' . $e->getMessage());
+            }
+        }
+
+        try {
+            $this->cache->purge($collectionKey);
+        } catch (Exception $e) {
+            Console::warning('Failed to purge collection cache key: ' . $e->getMessage());
+        }
-        try {
-            $this->cache->purge($collectionKey, $documentKey);
-            $this->cache->purge($documentKey);
-        } catch (Exception $e) {
-            Console::warning('Failed to purge document from cache: ' . $e->getMessage());
-        }
+        try {
+            $this->cache->purge($collectionKey, $documentKey);
+        } catch (Exception $e) {
+            Console::warning('Failed to purge document key from collection index: ' . $e->getMessage());
+        }
+
+        try {
+            $this->cache->purge($documentKey);
+        } catch (Exception $e) {
+            Console::warning('Failed to purge document cache key: ' . $e->getMessage());
+        }

Also applies to: 8248-8253

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Database/Database.php` around lines 8217 - 8226, The current try/catch
around the whole purge sequence causes a single exception from
$this->cache->list or $this->cache->purge to abort all further invalidation;
update the logic so each operation handles its own exceptions: wrap the call to
$this->cache->list(...) in a try/catch and handle/log failures, then iterate
over the returned $documentKeys and call $this->cache->purge($documentKey)
inside its own try/catch so one failing key doesn't stop others, and finally
call $this->cache->purge($collectionKey) in a separate try/catch with
Console::warning on error; apply the same per-operation try/catch refactor to
the analogous block that uses the same $this->cache->list / purge calls around
lines 8248-8253.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/Database/Database.php`:
- Around line 8217-8226: The current try/catch around the whole purge sequence
causes a single exception from $this->cache->list or $this->cache->purge to
abort all further invalidation; update the logic so each operation handles its
own exceptions: wrap the call to $this->cache->list(...) in a try/catch and
handle/log failures, then iterate over the returned $documentKeys and call
$this->cache->purge($documentKey) inside its own try/catch so one failing key
doesn't stop others, and finally call $this->cache->purge($collectionKey) in a
separate try/catch with Console::warning on error; apply the same per-operation
try/catch refactor to the analogous block that uses the same $this->cache->list
/ purge calls around lines 8248-8253.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e9fcb43b-68db-4629-bb80-83b25ebe6791

📥 Commits

Reviewing files that changed from the base of the PR and between ee2d7d4 and 3a51eaa.

📒 Files selected for processing (1)
  • src/Database/Database.php

@abnegate abnegate closed this Apr 17, 2026
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