You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* feat(db): add per-user CachedSettingsStore decorator
SettingsStore methods hit the database on every call. The v2 engine
path (effect_adapter) and the dispatcher's per-turn tool permission
loading both called get_all_settings() without caching, adding
unnecessary DB round-trips on every agentic loop iteration.
Add a write-through CachedSettingsStore decorator that caches
get_all_settings() results per user_id. Write operations (set_setting,
delete_setting, set_all_settings) delegate to the inner store then
invalidate that user's cache entry. The write lock is held across DB
loads to prevent stale-data races from concurrent invalidations.
Wire the cache into TenantScope via a new settings_store field on
AgentDeps, so all settings reads in the agent loop go through the
cache. Remove the per-turn cached_tool_permissions Mutex hack from
ChatDelegate that was working around the missing cache layer.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address PR review feedback
- Store Arc<HashMap> in cache instead of bare HashMap to avoid cloning
the full settings map on every cache hit. get_setting/has_settings now
only clone the single requested value or check emptiness through the Arc.
- Route get_setting_with_admin_fallback() through self.settings() instead
of self.inner so both the per-user and admin lookups go through the cache.
- Update settings section comment to accurately describe which methods
delegate through settings().
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address all PR review feedback
- Use `crate::db::` imports instead of `super::` (convention fix)
- Add `wrap()` factory fn to CachedSettingsStore, simplify app.rs construction
- Store `Arc<HashMap>` in cache to avoid full map clones on hits
- Expose `invalidate_user()` and `flush()` public methods
- Wire `flush()` into SIGHUP handler via concrete `settings_cache` on AppComponents
- Wire `settings_store` into GatewayState and route all settings handlers
through it so web UI writes invalidate the cache (critical fix)
- Route `get_setting_with_admin_fallback()` through `self.settings()`
- Add error-path test (FailingStore mock, cache not poisoned on error)
- Add concurrent-access test (8 concurrent readers, inner store hit once)
- Add TenantScope caller-level test (read/write through cache wiring)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: reuse resolve_settings_store() in settings_tools_set_handler
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address all review feedback on CachedSettingsStore
- Add TTL (300s) and max-entries cap (1000) to bound cache staleness
and memory growth. Entries expire after TTL; cache clears when cap
exceeded.
- Route admin tool_policy GET/PUT through resolve_settings_store() so
writes invalidate the __admin__ cache entry.
- Route settings_export_handler and settings_tools_list_handler through
resolve_settings_store() (were bypassing cache on reads).
- Wire invalidate_user() into users_delete_handler and
users_suspend_handler so deleted/suspended users' settings are evicted.
- Replace GatewayState.settings_store (trait object) with
settings_cache (concrete CachedSettingsStore) — single field for both
trait dispatch and cache management, no desync risk.
- Add settings_override to ExtensionManager with with_settings_store()
builder. All settings reads/writes in ExtensionManager now route
through the cached store when available.
- Make ExtensionManager::settings_store() pub(crate); update
AuthManager to call it instead of database(), closing the auth
descriptor cache bypass.
- Remove unused wrap() method; merge redundant invalidate/invalidate_user.
- Add tracing::debug on SIGHUP cache flush.
- Expand module docs with design assumptions, known bypass paths, TTL
and eviction semantics.
- Add tests: expired_entry_triggers_reload, fresh_entry_does_not_reload,
max_entries_cap_triggers_eviction.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: collapse nested if into filter to satisfy clippy
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
0 commit comments