#43 Log swallowed TryGetAsync exceptions - #52
Merged
Merged
Conversation
matthewdevenny
force-pushed
the
matt/43-trygetasync
branch
from
July 1, 2026 22:25
c041d58 to
ff1b729
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds explicit logging for exceptions that are swallowed by NatsCache.TryGetAsync (to honor the IBufferDistributedCache “return false on failure” behavior) and introduces test utilities + an integration test to assert the behavior.
Changes:
- Add a dedicated debug log method (
LogSwallowedException) and call it fromTryGetAsync’s exception handler. - Introduce an in-memory
RecordingLogger<T>for capturing log entries in tests. - Add an integration test that forces a read-path failure and asserts
TryGetAsyncreturnsfalseand logs the swallowed exception.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| test/TestUtils/Services/Logging/RecordingLogger.cs | Adds an in-memory test logger to capture ILogger calls for assertions. |
| test/IntegrationTests/Cache/TryGetAsyncTests.cs | Adds an integration test asserting swallowed exceptions are logged and TryGetAsync returns false. |
| src/NatsDistributedCache/NatsCache.Log.cs | Adds a new debug logging helper for swallowed exceptions. |
| src/NatsDistributedCache/NatsCache.cs | Updates TryGetAsync to log swallowed exceptions. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Signed-off-by: Matthew DeVenny <matt@codecargo.com>
Refine the TryGetAsync logging so a swallowed read failure is surfaced without being logged twice, and handle cancellation intentionally. - Log the swallowed exception at Warning (was Debug) so a real read failure such as NATS connectivity stays visible in production and is distinguishable from a normal cache miss. - Propagate OperationCanceledException from a cancelled caller token instead of swallowing it into a false miss (and do not log it). - Move exception logging out of the shared helpers (the lazy KV-store factory and GetAndRefreshAsync) up to the operation boundaries so each failure is logged exactly once: Error when it propagates to the caller (Get/Set/Refresh/Remove), Warning when TryGetAsync swallows it. This removes the previous double-log for connectivity errors. - Rename the private remove helper to RemoveCoreAsync to resolve an overload ambiguity created by routing sync Remove through the logging public RemoveAsync. - Expand the integration tests: swallow logs once at Warning, a propagating read logs once at Error, and cancellation propagates without being logged as an exception. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Matthew DeVenny <matt@codecargo.com>
matthewdevenny
force-pushed
the
matt/43-trygetasync
branch
from
July 2, 2026 03:17
cad5dff to
5e80386
Compare
matthewdevenny
marked this pull request as ready for review
July 2, 2026 15:51
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #43.
Problem
NatsCache.TryGetAsync(string, IBufferWriter<byte>, …)caught all exceptions and returnedfalsewith no logging. A NATS connectivity error was indistinguishable from a normal cache miss and left no diagnostic trail.What changed
TryGetAsyncnow logs a swallowed read failure, and the read path is reworked so each failure is logged exactly once.Exceptionevent id (101). Still returnsfalse, preserving theIBufferDistributedCachecontract.OperationCanceledExceptionfrom a cancelled caller token is no longer swallowed into afalsemiss (and is not logged) — cooperative cancellation isn't a cache failure.GetAndRefreshAsync) up to the operation boundaries, so each failure is logged once:Get/Set/Refresh/Remove) → Error, then rethrow.TryGetAsyncswallow → Warning.SetAsyncresolves the store inside its loggedtry; the private remove helper is renamedRemoveCoreAsyncto resolve an overload ambiguity when routing syncRemovethrough the logging publicRemoveAsync.Behavior notes
Removefailures are now consistently logged at Error (aDeleteAsyncfailure was previously logged inconsistently or not at all).TryGetAsyncnow throws on caller cancellation instead of returningfalse— the idiomatic .NET behavior, and a deliberate change from the original "swallow everything" semantics.Tests
New
test/IntegrationTests/Cache/TryGetAsyncTests.cs, using an in-memoryRecordingLogger<NatsCache>added to TestUtils (no new package dependency, so lock files are untouched):TryGetAsyncon a nonexistent bucket → returnsfalse, writes nothing, logs exactly one Warning.GetAsyncon a nonexistent bucket → throws, logs exactly one Error (guards against the helpers double-logging).TryGetAsyncwith a cancelled token → throwsOperationCanceledException, no exception logged.Verification
TreatWarningsAsErrors=true.dotnet format --verify-no-changespasses.Acceptance criteria
falseon failure; cancellation now propagates by design).