Skip to content

v1.0.40 - #106

Merged
yilmaztayfun merged 11 commits into
release-v1.0from
master
Sep 11, 2026
Merged

yilmaztayfun merged 11 commits into
release-v1.0from
master

Conversation

@yilmaztayfun

@yilmaztayfun yilmaztayfun commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Summary by Sourcery

Correct Dapr distributed-cache TTL handling to prevent stale permanent entries and accurately document provider-specific expiration behavior.

Bug Fixes:

  • Fix Dapr cache expiration so sub-second and fractional TTLs are rounded up to the provider’s one-second granularity instead of becoming permanent or expiring early.
  • Skip Dapr cache writes for already-expired or non-positive lifetimes and clamp excessively large TTLs to the supported integer range.

Enhancements:

  • Unify absolute and sliding TTL handling while preserving absolute-expiration precedence and improving TTL telemetry.

Documentation:

  • Document cache TTL granularity and provider-specific expiration behavior, including Dapr’s rounding, sliding-expiration limitations, and stale-entry upgrade considerations.
  • Correct distributed-cache expiration examples and add local NuGet feed usage instructions.

Tests:

  • Add unit coverage for Dapr TTL rounding, expiration handling, precedence, missing options, skipped writes, and large TTL clamping.

Chores:

  • Add design and implementation planning documentation for the Dapr cache TTL fix.

yilmaztayfun and others added 11 commits September 8, 2026 15:27
.local-feed/ (the repo-local NuGet feed written by build/pack-local.sh and consumed by vnext as
../aether/.local-feed) was ignored only through .git/info/exclude, which is per clone; a fresh
checkout following the local-feed procedure saw an untracked directory. It is now in the
committed .gitignore.

CLAUDE.md's NuGet section only described the release-v* publishing job; it now also documents the
local feed: pack-local.sh usage, the -local version rule, why the script purges the NuGet cache
before packing, the consumer-side wiring in vnext (nuget.config source + packageSourceMapping,
AetherPackageVersion) and the revert-before-PR rule, with a link to the full procedure in vnext.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
chore: ignore .local-feed/ and document build/pack-local.sh in CLAUDE.md
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…rever

DaprDistributedCacheService truncated the requested expiry to whole seconds
and dropped the ttlInSeconds metadata when the result was zero, which Dapr
reads as "no expiry" — the shortest lifetime a caller can ask for became the
longest one. The absolute and sliding branches also disagreed on what a
sub-second request meant.

Both branches now share one computation that rounds up and never falls below
the store's one-second granularity.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…over

An absolute expiry in the past, or a non-positive sliding expiration, means the
entry is already dead. Storing it was writing a permanent entry. The write is
now skipped and the span carries cache.skipped=true.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…gative

DateTimeOffset.MaxValue as an absolute expiry wrapped the unchecked int cast to
int.MinValue, sending a negative ttlInSeconds to the state store.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…xample

Documents Dapr's one-second floor and the round-up behaviour, and replaces the
AbsoluteExpirationRelativeToNow example — that property does not exist on
DistributedCacheEntryOptions.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The Basic Get/Set sample used the same non-existent property that the
Expiration Options sample did, so a reader copying it still got a compile
error.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…he skip

The span tags the design cited as a substitute for logging only exist under
the Verbose tracing profile, so a skipped write is silent by default; the
skip is also reachable from GetOrSetAsync whenever the fetch outlives a
short absolute expiry, which the design wrongly called a caller bug. Both
are now recorded, along with the upgrade note for entries already stored
without a TTL, the per-provider meaning of cache.ttl_seconds, and the
unspecified out-of-range cast behaviour that made the overflow test
unreproducible on ARM64.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
fix(cache): a sub-second TTL no longer becomes a permanent entry on the Dapr provider
@yilmaztayfun yilmaztayfun self-assigned this Sep 11, 2026
@yilmaztayfun
yilmaztayfun requested review from a team September 11, 2026 13:06

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Sorry @yilmaztayfun, you've used your own review budget of 250,000 diff characters for the last 7 days.

You can request another review in 4 days by commenting @sourcery-ai review. Upgrade to get a review now.

@coderabbitai

coderabbitai Bot commented Sep 11, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 3db1a354-5ef8-4c87-ab32-73d58891826a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@yilmaztayfun
yilmaztayfun merged commit 433ff1a into release-v1.0 Sep 11, 2026
5 of 6 checks passed
@codacy-production

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 14 complexity · 0 duplication

Metric Results
Complexity 14
Duplication 0

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@sourcery-ai

sourcery-ai Bot commented Sep 11, 2026

Copy link
Copy Markdown

Reviewer's Guide

Version 1.0.40 fixes Dapr distributed-cache TTL loss and truncation by centralizing expiration handling, rounding positive TTLs up to Dapr’s one-second granularity, skipping already-expired writes, and clamping extreme values. It adds focused unit tests, expands cache documentation and migration guidance, and documents the implementation/design plus local NuGet packaging workflow.

Sequence diagram for Dapr cache TTL handling

sequenceDiagram
    participant Caller
    participant Cache as DaprDistributedCacheService
    participant Dapr as DaprClient

    Caller->>Cache: SetAsync(key, value, options)
    Cache->>Cache: Compute requestedTtl
    alt requestedTtl <= TimeSpan.Zero
        Cache->>Cache: SetTag(cache.skipped, true)
        Cache-->>Caller: Return without SaveStateAsync
    else positive requestedTtl
        Cache->>Cache: ToStoreTtlSeconds(ttl)
        Cache->>Cache: Round up and clamp to int.MaxValue
        Cache->>Dapr: SaveStateAsync(..., ttlInSeconds metadata)
        Dapr-->>Cache: Save completed
        Cache-->>Caller: Return
    else no expiration options
        Cache->>Dapr: SaveStateAsync(..., no TTL metadata)
        Dapr-->>Cache: Save completed
        Cache-->>Caller: Return
    end
Loading

File-Level Changes

Change Details Files
Correct Dapr TTL conversion and handling of expired cache writes.
  • Unify absolute and sliding expiration calculation while preserving absolute-expiration precedence.
  • Round positive lifetimes up to Dapr’s one-second granularity and clamp oversized values to int.MaxValue.
  • Skip writes for already-expired absolute or non-positive sliding lifetimes, recording a diagnostic tag.
  • Use invariant formatting for ttlInSeconds metadata.
framework/src/BBT.Aether.Infrastructure/BBT/Aether/DistributedCache/Dapr/DaprDistributedCacheService.cs
Add unit coverage for Dapr cache expiration behavior.
  • Capture SaveStateAsync metadata with a substituted DaprClient.
  • Verify sub-second and fractional TTL rounding, whole-second values, precedence, no-options behavior, skipped writes, and large-value clamping.
framework/test/BBT.Aether.Infrastructure.Tests/BBT/Aether/DistributedCache/Dapr/DaprDistributedCacheServiceTests.cs
Document provider-specific cache TTL semantics and migration implications.
  • Fix the invalid relative-expiration example.
  • Document Dapr’s one-second floor, round-up behavior, non-positive expiration handling, non-sliding Dapr reads, telemetry differences, and stale entries from earlier versions.
framework/docs/distributed-cache/README.md
Add design and implementation documentation for the Dapr TTL fix.
  • Record the defect analysis, scope decisions, compatibility impact, test plan, and implementation workflow.
  • Document local NuGet feed packaging and consumption guidance for unreleased work.
framework/docs/superpowers/specs/2026-09-11-dapr-cache-ttl-granularity-design.md
framework/docs/superpowers/plans/2026-09-11-dapr-cache-ttl-granularity.md
CLAUDE.md
.gitignore

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sonarqubecloud

Copy link
Copy Markdown

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