Skip to content

Add lightweight post-removal observer to future::Cache - #607

Open
javaquasar wants to merge 2 commits into
moka-rs:mainfrom
javaquasar:feature/post-removal-observer
Open

javaquasar wants to merge 2 commits into
moka-rs:mainfrom
javaquasar:feature/post-removal-observer

Conversation

@javaquasar

@javaquasar javaquasar commented Sep 27, 2026 •

Copy link
Copy Markdown

Summary

This PR adds a lightweight synchronous post_removal_observer to future::Cache for callers
that only need to publish a small removal record without enabling eviction-listener futures or the
listener-only per-key lock map.

The public contract is intentionally left open for maintainer feedback. Discussion:
#606

Motivation

The existing eviction listener is the right API for asynchronous work and per-key serialization.
For a nonblocking accounting callback, however, a no-op listener has measurable fixed allocation
cost. In five fresh release processes per mode/operation pair, median allocation count relative to
notification-off changed by:

Operation No-op listener No-op observer
Insert +46.73% 0.00%
Explicit remove +784.63% +0.03%

The benchmark classifies allocation ownership; it is not an elapsed-time performance claim. Raw
data, environment metadata, exact commands, and checksums are linked from the Discussion.

Prototype contract

  • Scoped to future::Cache.
  • Receives Arc<K>, cloned V, and RemovalCause after logical removal.
  • Covers Explicit, Replaced, Expired, and Size.
  • May execute concurrently and must remain fast and nonblocking.
  • Runs before an eviction listener when both are configured.
  • A panic is contained and disables subsequent observer calls.
  • Does not enable listener-only key locks.
  • Does not add cache-drop notifications or wait for caller-owned deferred work.

Validation

  • 18 focused observer tests, including all removal causes, TTL/TTI, all invalidation paths,
    Entry/compute paths, cancellation, concurrency, panic isolation, ordering, custom hashers, and a
    bounded nonblocking queue.
  • cargo test --all-features
  • cargo test --locked --no-default-features --features future
  • cargo clippy --lib --tests --all-features --all-targets -- -D warnings
  • cargo fmt --all -- --check
  • cargo run --example post_removal_observer_async --features future
  • RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --features future
  • cargo package --allow-dirty --features future --no-verify
  • Fork CI: stable/beta/nightly/MSRV, Quanta, cross-compile, Loom, Kani, Trybuild, and lints passed.

The fork's Miri workflow reproduces an existing sync-only
timer_wheel_panic_test/parking_lot_core futex failure. The failing stack contains neither the
observer nor future::Cache code.

Review focus

I would especially appreciate maintainer guidance on:

  1. whether this should be a separate API;
  2. naming and future::Cache-only scope;
  3. coexistence and ordering with eviction listeners; and
  4. concurrency, panic, drop, and run_pending_tasks semantics.

Summary by CodeRabbit

  • New Features
    • Added an experimental post-removal observer for future caches. It receives the removed key, value, and removal cause after invalidation, replacement, expiration, or size-based eviction.
    • The synchronous callback runs before the asynchronous eviction listener starts when both are configured. Calls may overlap; if the callback panics, it is disabled for subsequent removals.
    • Added an async example that forwards removal notifications through a bounded queue and handles rejected sends without blocking.

@coderabbitai

coderabbitai Bot commented Sep 27, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: moka-rs/moka/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: a39ef3f8-c3c2-4cea-8cbb-fec05e12eb61
📥 Commits

Reviewing files that changed from the base of the PR and between e91c654 and fc3c0d4.

📒 Files selected for processing (6)
  • CHANGELOG.md
  • examples/post_removal_observer_async.rs
  • src/future/builder.rs
  • src/future/cache.rs
  • src/future/observer.rs
  • src/notification.rs
🚧 Files skipped from review as they are similar to previous changes (3)
  • CHANGELOG.md
  • src/notification.rs
  • src/future/observer.rs

Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

Future caches gain an optional synchronous post-removal observer. It receives the removed key, value, and removal cause. Removal paths invoke it alongside any configured asynchronous eviction listener. The change also adds tests, an example, and documentation.

Changes

Post-removal observation

Layer / File(s) Summary
Observer API and cache construction
src/notification.rs, src/future/builder.rs, src/future/cache.rs, src/future/base_cache.rs
Adds the callback type and builder setter. Passes the configured observer through cache construction, including custom-hasher builds.
Removal dispatch and observer behavior
src/future/observer.rs, src/future/base_cache.rs, src/future/cache.rs, src/future/invalidator.rs
Invokes the observer for removals, replacements, and invalidations. The callback runs synchronously before an optional async eviction listener. Tests cover removal causes, callback ordering, panic handling, concurrency, cancellation, and nonblocking queue use.
Example and documentation
examples/post_removal_observer_async.rs, Cargo.toml, CHANGELOG.md, src/future/cache.rs
Adds a feature-gated example that sends removal tickets through a bounded channel without waiting. Documents the experimental API and callback behavior.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant CacheBuilder
  participant BaseCache
  participant PostRemovalObserver
  participant AsyncEvictionListener
  CacheBuilder->>BaseCache: pass configured observer during construction
  BaseCache->>PostRemovalObserver: invoke synchronously with key, value, and cause
  BaseCache->>AsyncEvictionListener: await listener when configured
Loading

Merge Risk: ⚪ Minimal · up to fc3c0

No identified issue currently prevents merging after normal checks.

Security Architecture Review

Security architecture risk: 🔵 Low · up to fc3c0

The observer is opt-in, receives data already available to eviction listeners, and contains callback panics. No introduced security defect was established. Safe integration still depends on nonblocking, non-reentrant callbacks and application-owned handling of delivery failures; downstream integrations were not available for review.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The directly evidenced exposure is the configured cache's removed keys and values and the thread or task processing removal. A blocking callback can stall that execution path. Remote reachability, tenant scope, and downstream publication depend on application integrations not supplied here.

Trust Boundaries and Controls

  • observed — The cache caller installs a Send and Sync callback receiving the same key/value/cause payload exposed by the existing eviction-listener API. The callback signature introduces no cache-internal capability or credential argument; downstream authority comes from caller-provided callback code.

Resilience and Maintainability Implications

  • observed — The observer catches callback unwinding and atomically disables later calls, without disabling the separate listener. Calls already past the enabled check may finish concurrently. This contains unwinding but does not provide durable record delivery, consistent with the documented contract and the existing listener's panic-disable policy.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.15% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 65 functions across 8 files. (1 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely identifies the main change: adding a post-removal observer to future::Cache.
Full details: Docstring Coverage

Explanation

Docstring coverage is 66.15% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 65 functions across 8 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR

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.

@javaquasar

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Sep 27, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@javaquasar
javaquasar marked this pull request as ready for review October 4, 2026 10:28
@javaquasar

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Oct 4, 2026 •

Copy link
Copy Markdown
⚠️ Action not completed

Already reviewed the last commit. Use @coderabbitai full review to rerun a review of the entire changeset.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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