#17657: fix: clear QMD manager cache on in-process restart (SIGUSR1)
gateway
cli
stale
size: XS
Cluster:
QMD Memory Management Fixes
## Problem
The `QMD_MANAGER_CACHE` (module-level `Map` in `search-manager.ts`) persists across in-process restarts triggered by SIGUSR1. Config changes to QMD scope, collections, command path, or other memory settings do not take effect until a full process kill (`kill -9`).
### Reproduction Steps
1. Set `memory.qmd.scope.default: "deny"` (the default)
2. Start the gateway
3. Verify `memory_search` is denied in guild channels (expected)
4. Patch config: `memory.qmd.scope.default: "allow"`
5. Gateway restarts via SIGUSR1
6. `memory_search` is **still denied** in guild channels (bug)
7. Only `kill -9` + restart makes the scope change take effect
### Root Cause
`getMemorySearchManager()` caches managers in a module-level `Map` keyed by `agentId + serialized config`. After SIGUSR1, the gateway reloads config, but the old cached manager (created with the pre-restart config) is still returned for existing sessions because the module-level Map survives the in-process restart.
## Fix
- Export `clearQmdManagerCache()` from `search-manager.ts` that properly closes all cached managers and clears the Map
- Call it from the restart iteration hook in `run-loop.ts`, alongside the existing `resetAllLanes()` call
This ensures QMD scope, collection, and command changes take effect immediately after `config.patch` / `config.apply` restarts.
## Changes
- `src/memory/search-manager.ts`: Add `clearQmdManagerCache()` export
- `src/cli/gateway-cli/run-loop.ts`: Import and call on restart iteration
## Testing
Manually verified on production instance:
1. Changed `scope.default` from `deny` → `allow`
2. Before fix: required `kill -9` to take effect
3. After fix: `config.patch` restart applies immediately
Related: #15093 (QMD reliability improvements)
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
This PR fixes a bug where the module-level `QMD_MANAGER_CACHE` in `search-manager.ts` persists across in-process restarts (SIGUSR1), causing memory config changes (scope, collections, command path) to not take effect until a full `kill -9`.
The fix introduces `clearQmdManagerCache()` and invokes it from two restart paths:
- **SIGUSR1 in-process restart** (`run-loop.ts`): called in the restart iteration hook alongside `resetAllLanes()`
- **Hot-reload via config file watcher** (`server-reload-handlers.ts`): called when `plan.restartMemory` is true, enabled by a new `"memory"` prefix hot-reload rule in `config-reload.ts`
The implementation follows the established patterns for other subsystem restarts (cron, heartbeat, browser-control). New tests verify that `memory.*` config changes produce a hot-reload plan rather than requiring a full gateway restart.
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge — it adds a targeted cache-clearing mechanism with no impact on the happy path.
- The changes are minimal and well-scoped: a new export function that clears a module-level Map, integrated into two existing restart paths following established patterns. The code is correct (Map delete-during-iteration is spec-safe in JS, fire-and-forget close is appropriate for restart paths). Tests cover the config-reload plan logic. No regressions are likely since clearQmdManagerCache only runs during restart/reload events and the existing getMemorySearchManager logic is unchanged.
- No files require special attention.
<sub>Last reviewed commit: 00ce621</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#10801: fix: eagerly initialize QMD memory backend on gateway startup
by 1kuna · 2026-02-07
80.4%
#16917: fix(memory): close stale SQLite connection after qmd update
by zerone0x · 2026-02-15
79.8%
#9381: Fix: Allow QMD CLI memory search when scope is restrictive
by vishaltandale00 · 2026-02-05
78.5%
#9149: Fix: Allow QMD backend to work without OpenAI auth
by vishaltandale00 · 2026-02-04
78.1%
#21471: fix: check QMD backend before memory search config
by lbo728 · 2026-02-20
77.4%
#9624: fix(memory): resolve QMD search returning empty results [AI-assisted]
by kowshik24 · 2026-02-05
76.8%
#22937: fix: remove legacy unsuffixed QMD collections on upgrade
by sud0n1m-ziggy · 2026-02-21
76.5%
#20125: fix(doctor): skip memorySearch provider check when using QMD backend
by brandonwise · 2026-02-18
76.4%
#11179: fix(memory): replace confusing "No API key" errors in memory tools ...
by liuxiaopai-ai · 2026-02-07
76.4%
#20966: fix(memory/qmd): migrate orphaned unscoped collections on upgrade
by marcodelpin · 2026-02-19
76.2%