#38 add bucket auto creation option - #53
Merged
Merged
Conversation
Signed-off-by: Matthew DeVenny <matt@codecargo.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds an opt-in capability for NatsCache to automatically create (and currently also update) the backing NATS KV bucket on first cache use, with cache-required defaults (LimitMarkerTTL, History = 1) and an optional configuration hook. This addresses issue #38 by making the README’s manual bucket pre-creation step optional.
Changes:
- Introduces
CreateBucketIfNotExistsandConfigureBucketonNatsCacheOptions, plusNatsCachelogic to create/update the KV bucket on first use. - Updates README and
util/ReadmeExample/*samples to demonstrate the new opt-in behavior (and remove mandatory pre-create snippets). - Adds unit + integration tests covering bucket config defaults, override hook behavior, and end-to-end auto-creation.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| util/ReadmeExample/HybridCache.Example.cs | Updates sample to enable opt-in auto bucket creation; removes manual KV creation code. |
| util/ReadmeExample/HybridCache.cs | Updates Aspire-based sample to enable opt-in auto bucket creation; removes manual KV creation. |
| util/ReadmeExample/DistributedCache.Example.cs | Updates sample to enable opt-in auto bucket creation; removes manual KV creation code. |
| util/ReadmeExample/DistributedCache.cs | Updates Aspire-based sample to enable opt-in auto bucket creation; removes manual KV creation. |
| test/UnitTests/Extensions/NatsDistributedCacheExtensionsTests.cs | Adds tests ensuring new options are wired and default disabled contract holds. |
| test/UnitTests/Cache/BucketConfigUnitTests.cs | Adds focused unit tests for BuildBucketConfig defaults and hook behavior. |
| test/IntegrationTests/Cache/BucketAutoCreationTests.cs | Adds integration coverage validating bucket auto-creation on first cache operation. |
| src/NatsDistributedCache/NatsCacheOptions.cs | Adds public options (CreateBucketIfNotExists, ConfigureBucket) with API docs. |
| src/NatsDistributedCache/NatsCache.cs | Implements lazy create/update bucket behavior and BuildBucketConfig defaults/hook. |
| README.md | Documents optional automatic bucket creation and adds configuration examples. |
Comments suppressed due to low confidence (1)
README.md:18
- The manual bucket-creation snippet only sets
LimitMarkerTTL, but the new auto-creation path and docs state per-key TTL requiresHistory = 1as well. To avoid inconsistent guidance and make the requirements explicit, update the snippet to setHistory = 1too.
```csharp
// assuming an INatsConnection natsConnection
var kvContext = natsConnection.CreateKeyValueStoreContext();
await kvContext.CreateOrUpdateStoreAsync(new NatsKVConfig("cache") { LimitMarkerTTL = TimeSpan.FromSeconds(1) });
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Only create a missing bucket; never update an existing (operator-managed) one, so the behavior matches the CreateBucketIfNotExists name. Check GetBucketNamesAsync and use CreateStoreAsync instead of CreateOrUpdateStoreAsync. - Guard against ConfigureBucket returning null with a clear InvalidOperationException. - Docs: reflect create-only semantics; show History = 1 in the manual snippet. - Tests: add null-guard unit test and an integration test asserting an existing bucket is left unmodified. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Matthew DeVenny <matt@codecargo.com>
- GetOrCreateStoreAsync now tries GetStoreAsync first and creates only on the JetStream "stream not found" error (ErrCode 10059). Avoids the O(n) GetBucketNamesAsync list call and its stream-list permission requirement; other errors (connectivity, auth) propagate unchanged. - README: make the manual pre-create snippet self-contained with the required NATS.Client.KeyValueStore / NATS.Net usings. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Matthew DeVenny <matt@codecargo.com>
Use `ex.Error is { ErrCode: StreamNotFoundErrCode }` so a null Error makes the
catch filter evaluate false instead of throwing (which would silently skip
auto-creation of a missing bucket).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Matthew DeVenny <matt@codecargo.com>
matthewdevenny
marked this pull request as ready for review
July 6, 2026 18:34
mtmk
approved these changes
Jul 6, 2026
Per review feedback, the hook only applies when a missing bucket is first created (it's a no-op for an existing bucket). The clearer name reflects that. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Matthew DeVenny <matt@codecargo.com>
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.
Summary
Adds opt-in automatic creation of the backing NATS KV bucket, so consumers no longer have to pre-create it before using the cache. Closes #38.
Previously
NatsCacheonly calledGetStoreAsync(bucketName), which fails if the bucket doesn't exist — every consumer had to run a manualCreateOrUpdateStoreAsync(...)step (the most prominent step in the README). This makes that step optional.What's new
NatsCacheOptions.CreateBucketIfNotExists(defaultfalse) — when enabled, the bucket is created on first cache use if it is missing, with the settings per-key TTL requires:History = 1and a non-zeroLimitMarkerTTL.NatsCacheOptions.ConfigureBucket(Func<NatsKVConfig, NatsKVConfig>) — optional hook to customize storage / replication / limits.NatsKVConfigis an immutable record, so it's used with awithexpression (the same idiom already used forNatsOptselsewhere in this repo):Behavior / design notes
GetStoreAsyncis attempted first, and only if it reports the bucket is missing (JetStream "stream not found") doesCreateStoreAsynccreate it. An existing operator-managed bucket is used as-is and never modified, so the option name matches the behavior. Probing withGetStoreAsync(rather than listing every bucket) keeps this O(1) and needs no stream-list permission; any other error propagates unchanged.IHostedService/ startup coupling, so a brief NATS outage at boot doesn't fail host startup.History = 1and a non-zeroLimitMarkerTTL, then appliesConfigureBucket; theBucketname is always re-asserted afterward. AConfigureBucketthat returnsnullthrows a clearInvalidOperationException.Docs
README requirements and both examples now show the opt-in flag, plus a new "Automatic bucket creation" section documenting
ConfigureBucketand its caveats. Theutil/ReadmeExample/*samples were updated to match (manual pre-create step removed).Testing
BuildBucketConfigdefaults / hook override / null guard, and options plumbing + defaults-to-disabled contract.History = 1+LimitMarkerTTL; and verifies an existing operator-managed bucket is left unmodified.ReadmeExampleapp end-to-end against a fresh NATS container — both the DistributedCache and HybridCache examples work with no manual bucket step.🤖 Generated with Claude Code