-
Notifications
You must be signed in to change notification settings - Fork 0
docs: drop moka, update cache docs for PortableCache (whatsapp-rust#860) #327
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 1 commit
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| --- | ||
| title: "June 14, 2026 — Drop moka: PortableCache is now the sole in-process cache backend" | ||
| description: "Removes the moka dependency (-2.55 MiB stripped, -21% .text). PortableCache gains monotonic TTL/TTI, eager init-lock reclamation, and a reliable async clear(). TypedCache::from_moka is renamed to from_local." | ||
| --- | ||
|
|
||
| PR [#860](https://github.com/oxidezap/whatsapp-rust/pull/860) removes the `moka` dependency and makes `PortableCache` the only in-process cache backend on every target, including wasm32. | ||
|
|
||
| ## Why moka was removed | ||
|
|
||
| `moka` was the single largest contributor to the release binary — **1.8 MiB of `.text` (15.8%)** — almost entirely from per-cache-type monomorphization. Its `do_run_pending_tasks` alone was emitted **84 times (710 KiB)** across the ~15 distinct `Cache` types the client instantiates; each new typed cache dragged in moka's full generic machinery (~100 KiB+). | ||
|
|
||
| `PortableCache` was already shipping on wasm32 targets and mirrors the full moka `Cache` API (capacity + TTL/TTI eviction, single-flight `get_with`/`get_with_by_ref`). Making it the sole backend required no call-site changes. | ||
|
|
||
| ## Binary size impact | ||
|
|
||
| Real release profile (fat LTO, `codegen-units=1`, `panic=abort`, strip): | ||
|
|
||
| | Metric | before (moka) | after (PortableCache) | Δ | | ||
| |---|---:|---:|---:| | ||
| | Stripped size | 13.35 MiB | 10.81 MiB | **−2.55 MiB (−19.1%)** | | ||
| | `.text` | 11.31 MiB | 8.89 MiB | **−2.42 MiB (−21.4%)** | | ||
| | LLVM IR lines | 1,275,789 | 664,220 | **−47.9%** | | ||
| | `Cargo.lock` crates | 357 | 354 | −3 | | ||
|
|
||
| The net delta exceeds moka's own 1.8 MiB line because dropping moka also removes its transitive deps (crossbeam-channel/epoch, quanta, part of uuid) and unlocks further LTO savings. CodSpeed reports no performance change across 172 benchmarks. | ||
|
|
||
| ## PortableCache hardening | ||
|
|
||
| Making PortableCache the sole native backend surfaced a few behavioural gaps that were addressed in this PR: | ||
|
|
||
| - **Monotonic TTL/TTI** — expiry now uses `wacore::time::Instant` instead of the wall clock, so a system-clock jump can't expire entries early. This matches moka's timer semantics and prevents `session_recreate_history`'s throttle backstop from being bypassed. | ||
| - **Eager single-flight init-lock reclamation** — `get_with`/`get_with_by_ref` now drop a key's init lock once no other caller holds it, instead of waiting for `run_pending_tasks`. Fixes unbounded `init_locks` growth in high-cardinality caches (session locks, chat lanes, message-id dedup) that never call `run_pending_tasks`. | ||
| - **Reliable async `clear()`** — new `PortableCache::clear()` awaits the write lock. `cleanup_connection_state` and `TypedCache::clear` now use it instead of the best-effort sync `invalidate_all()`, which could skip the clear under contention and leave a stale `ChatLane` after reconnect. | ||
| - **`snapshot_entries()`** — new async method that awaits the read lock for a reliable snapshot; used by `SenderKeyDeviceCache::invalidate_entries_for_device` where a missed entry would silently drop an SKDM fanout. | ||
|
|
||
| ## Breaking changes | ||
|
|
||
| ### `moka-cache` feature removed | ||
|
|
||
| The `moka-cache` Cargo feature no longer exists. Remove it from your `Cargo.toml`: | ||
|
|
||
| ```toml | ||
| # Before | ||
| whatsapp-rust = { version = "0.6", default-features = false, features = [ | ||
| "sqlite-storage", "tokio-transport", "tokio-runtime", | ||
| "ureq-client", "tokio-native", "signal", | ||
| "moka-cache", # ← remove this line | ||
| ] } | ||
|
|
||
| # After | ||
| whatsapp-rust = { version = "0.6", default-features = false, features = [ | ||
| "sqlite-storage", "tokio-transport", "tokio-runtime", | ||
| "ureq-client", "tokio-native", "signal", | ||
| ] } | ||
| ``` | ||
|
|
||
| ### `TypedCache::from_moka` renamed to `from_local` | ||
|
jlucaso1 marked this conversation as resolved.
|
||
|
|
||
| If you construct a `TypedCache` directly in your own code, update the constructor name: | ||
|
|
||
| ```rust | ||
| // Before | ||
| let cache = TypedCache::from_moka(my_cache); | ||
|
|
||
| // After | ||
| let cache = TypedCache::from_local(my_cache); | ||
| ``` | ||
|
|
||
| ### `portable_cache` module is now always public | ||
|
|
||
| `whatsapp_rust::portable_cache` is no longer `cfg`-gated. Any conditional compilation on `#[cfg(any(not(feature = "moka-cache"), target_arch = "wasm32"))]` around imports of that module should be removed. | ||
|
|
||
| ## Trade-offs | ||
|
|
||
| `PortableCache` differs from moka in two ways relevant to very high-throughput deployments: | ||
|
|
||
| - **Eviction policy**: FIFO instead of TinyLFU (lower hit rate under heavily skewed access patterns) | ||
| - **Concurrency**: one `RwLock` per cache vs moka's sharded, lock-free reads (more contention under heavy concurrent access) | ||
|
|
||
| For typical bot/single-account workloads this is unlikely to matter; the integration benchmarks (CodSpeed) confirmed no performance change across all 172 benchmarks. | ||
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
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
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
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
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.
Uh oh!
There was an error while loading. Please reload this page.