mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 06:57:10 +00:00
Bound shared query and catalog context retention
This commit is contained in:
parent
c0e4fc590c
commit
b6f6d04147
4 changed files with 39 additions and 2 deletions
|
|
@ -32,6 +32,7 @@ import { cloneModelMetadata, cloneSharedServerMetadata, cloneThreads } from "./s
|
|||
const THREAD_LIST_STALE_TIME_MS = 10_000;
|
||||
const APP_SERVER_METADATA_STALE_TIME_MS = 10_000;
|
||||
const MODELS_STALE_TIME_MS = 60_000;
|
||||
const APP_SERVER_QUERY_GC_TIME_MS = 5 * 60_000;
|
||||
|
||||
export interface AppServerQueryClientRunner {
|
||||
runWithClient<T>(
|
||||
|
|
@ -388,7 +389,7 @@ function createAppServerQueryClient(): QueryClient {
|
|||
return new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
gcTime: Infinity,
|
||||
gcTime: APP_SERVER_QUERY_GC_TIME_MS,
|
||||
retry: false,
|
||||
refetchOnReconnect: false,
|
||||
refetchOnWindowFocus: false,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import type { ObservedResultListener } from "../../../app-server/query/observed-
|
|||
import type { Thread } from "../../../domain/threads/model";
|
||||
|
||||
type ThreadListObserver = ObservedResultListener<readonly Thread[]>;
|
||||
const MAX_RETAINED_THREAD_CATALOG_CONTEXTS = 4;
|
||||
|
||||
interface ThreadCatalogStore {
|
||||
contextKey(): string;
|
||||
|
|
@ -113,7 +114,20 @@ export function createThreadCatalog(options: ThreadCatalogOptions): ThreadCatalo
|
|||
|
||||
function threadCatalogFactsForContext(factsByContext: Map<string, ThreadCatalogFacts>, contextKey: string): ThreadCatalogFacts {
|
||||
const existing = factsByContext.get(contextKey);
|
||||
if (existing) return existing;
|
||||
if (existing) {
|
||||
factsByContext.delete(contextKey);
|
||||
factsByContext.set(contextKey, existing);
|
||||
return existing;
|
||||
}
|
||||
while (factsByContext.size >= MAX_RETAINED_THREAD_CATALOG_CONTEXTS) {
|
||||
let leastRecentlyUsed: string | undefined;
|
||||
for (const key of factsByContext.keys()) {
|
||||
leastRecentlyUsed = key;
|
||||
break;
|
||||
}
|
||||
if (leastRecentlyUsed === undefined) break;
|
||||
factsByContext.delete(leastRecentlyUsed);
|
||||
}
|
||||
const facts = {
|
||||
active: pendingThreadListFacts(),
|
||||
archived: pendingThreadListFacts(),
|
||||
|
|
|
|||
|
|
@ -17,6 +17,12 @@ import {
|
|||
import type { SharedServerMetadata } from "../../src/domain/server/metadata";
|
||||
|
||||
describe("AppServerQueryCache", () => {
|
||||
it("allows inactive query contexts to be garbage-collected", () => {
|
||||
const cache = new AppServerQueryCache();
|
||||
|
||||
expect(cache.client.getDefaultOptions().queries?.gcTime).toBe(300_000);
|
||||
});
|
||||
|
||||
it("preserves successful metadata resource values when probes fail", () => {
|
||||
const cache = new AppServerQueryCache();
|
||||
const context = cacheContext();
|
||||
|
|
|
|||
|
|
@ -194,6 +194,22 @@ describe("ThreadCatalog", () => {
|
|||
expect(catalog.activeSnapshot()).toEqual([thread("started-a")]);
|
||||
});
|
||||
|
||||
it("evicts lifecycle facts for least-recently-used connection contexts", () => {
|
||||
const context = { codexPath: "codex-a", vaultPath: "/vault" };
|
||||
const { catalog } = catalogFixture({ context: () => context });
|
||||
catalog.apply({ type: "thread-started", thread: thread("started-a") });
|
||||
|
||||
for (const suffix of ["b", "c", "d", "e"]) {
|
||||
context.codexPath = `codex-${suffix}`;
|
||||
catalog.activeSnapshot();
|
||||
}
|
||||
|
||||
context.codexPath = "codex-a";
|
||||
catalog.apply({ type: "active-list-snapshot-received", threads: [thread("server-a")] });
|
||||
|
||||
expect(catalog.activeSnapshot()).toEqual([thread("server-a")]);
|
||||
});
|
||||
|
||||
it("keeps rollback fork metadata until active snapshots catch up to the rollback version", () => {
|
||||
const { catalog } = catalogFixture();
|
||||
const forkBeforeRollback = thread("forked", false, { name: "Before", preview: "Before rollback", updatedAt: 20 });
|
||||
|
|
|
|||
Loading…
Reference in a new issue