perf(main): reuse cached runtime process table
This commit is contained in:
parent
53a4c0e9e6
commit
6bb8d87bc7
5 changed files with 58 additions and 10 deletions
|
|
@ -1,5 +1,6 @@
|
|||
import { TmuxStatusSourceAdapter } from '../adapters/output/sources/TmuxStatusSourceAdapter';
|
||||
import {
|
||||
type ListRuntimeProcessesOptions,
|
||||
type RuntimeProcessTableRow,
|
||||
type TmuxPaneRuntimeInfo,
|
||||
TmuxPlatformCommandExecutor,
|
||||
|
|
@ -34,10 +35,10 @@ export async function listTmuxPaneRuntimeInfoForCurrentPlatform(
|
|||
return runtimeCommandExecutor.listPaneRuntimeInfo(paneIds);
|
||||
}
|
||||
|
||||
export async function listRuntimeProcessTableForCurrentPlatform(): Promise<
|
||||
RuntimeProcessTableRow[]
|
||||
> {
|
||||
return runtimeCommandExecutor.listRuntimeProcesses();
|
||||
export async function listRuntimeProcessTableForCurrentPlatform(
|
||||
options: ListRuntimeProcessesOptions = {}
|
||||
): Promise<RuntimeProcessTableRow[]> {
|
||||
return runtimeCommandExecutor.listRuntimeProcesses(options);
|
||||
}
|
||||
|
||||
export async function sendKeysToTmuxPaneForCurrentPlatform(
|
||||
|
|
|
|||
|
|
@ -32,6 +32,10 @@ export interface RuntimeProcessTableRow {
|
|||
rssBytes?: number;
|
||||
}
|
||||
|
||||
export interface ListRuntimeProcessesOptions {
|
||||
bypassCache?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Short-lived cache window for the global process table.
|
||||
*
|
||||
|
|
@ -218,9 +222,11 @@ export class TmuxPlatformCommandExecutor {
|
|||
return new Map([...info.entries()].map(([paneId, pane]) => [paneId, pane.panePid]));
|
||||
}
|
||||
|
||||
async listRuntimeProcesses(): Promise<RuntimeProcessTableRow[]> {
|
||||
async listRuntimeProcesses(
|
||||
options: ListRuntimeProcessesOptions = {}
|
||||
): Promise<RuntimeProcessTableRow[]> {
|
||||
const cached = this.#runtimeProcessTableCache;
|
||||
if (cached && cached.expiresAtMs > Date.now()) {
|
||||
if (options.bypassCache !== true && cached && cached.expiresAtMs > Date.now()) {
|
||||
return cached.rows;
|
||||
}
|
||||
if (this.#runtimeProcessTableInFlight) {
|
||||
|
|
|
|||
|
|
@ -152,4 +152,39 @@ describe('TmuxPlatformCommandExecutor', () => {
|
|||
]);
|
||||
expect(childProcess.execFile).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('can bypass the runtime process table cache for fresh process reads', async () => {
|
||||
setPlatform('win32');
|
||||
const execInPreferredDistro = vi
|
||||
.fn()
|
||||
.mockResolvedValueOnce({
|
||||
exitCode: 0,
|
||||
stdout: ' 42 1 1.0 128 opencode runtime --team-name demo --agent-id alice@demo\n',
|
||||
stderr: '',
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
exitCode: 0,
|
||||
stdout: ' 43 1 1.0 128 opencode runtime --team-name demo --agent-id alice@demo\n',
|
||||
stderr: '',
|
||||
});
|
||||
const executor = new TmuxPlatformCommandExecutor(
|
||||
{
|
||||
execInPreferredDistro,
|
||||
getPersistedPreferredDistroSync: () => 'Ubuntu',
|
||||
} as never,
|
||||
{} as never
|
||||
);
|
||||
|
||||
await expect(executor.listRuntimeProcesses()).resolves.toEqual([
|
||||
expect.objectContaining({ pid: 42 }),
|
||||
]);
|
||||
await expect(executor.listRuntimeProcesses()).resolves.toEqual([
|
||||
expect.objectContaining({ pid: 42 }),
|
||||
]);
|
||||
await expect(executor.listRuntimeProcesses({ bypassCache: true })).resolves.toEqual([
|
||||
expect.objectContaining({ pid: 43 }),
|
||||
]);
|
||||
|
||||
expect(execInPreferredDistro).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -10522,6 +10522,7 @@ export class TeamProvisioningService {
|
|||
peekAutoResumeService()?.cancelPendingAutoResume(teamName);
|
||||
this.clearOpenCodeRuntimeToolApprovals(teamName, { emitDismiss: true });
|
||||
this.invalidateRuntimeSnapshotCaches(teamName);
|
||||
this.runtimeProcessRowsForUsageSnapshotByTeam.delete(teamName);
|
||||
this.retainedClaudeLogsByTeam.delete(teamName);
|
||||
this.persistedTranscriptClaudeLogsCache.delete(teamName);
|
||||
this.leadInboxRelayInFlight.delete(teamName);
|
||||
|
|
@ -25554,7 +25555,10 @@ export class TeamProvisioningService {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (processRowsReadForMetadata) {
|
||||
if (
|
||||
processRowsReadForMetadata &&
|
||||
this.getRuntimeSnapshotCacheGeneration(teamName) === generationAtStart
|
||||
) {
|
||||
const sampledAtMs = Date.now();
|
||||
this.runtimeProcessRowsForUsageSnapshotByTeam.set(teamName, {
|
||||
expiresAtMs:
|
||||
|
|
|
|||
|
|
@ -60,10 +60,12 @@ export async function cleanupManagedOpenCodeServeProcesses(
|
|||
diagnostics: [],
|
||||
};
|
||||
|
||||
const rows = await (
|
||||
const listProcessRows =
|
||||
options.listProcessRows ??
|
||||
(platform === 'win32' ? listWindowsProcessTable : listRuntimeProcessTableForCurrentPlatform)
|
||||
)();
|
||||
(platform === 'win32'
|
||||
? listWindowsProcessTable
|
||||
: () => listRuntimeProcessTableForCurrentPlatform({ bypassCache: true }));
|
||||
const rows = await listProcessRows();
|
||||
const excludePids = options.excludePids ?? new Set<number>();
|
||||
const requiredDetailsMarkers = options.requiredDetailsMarkers ?? [];
|
||||
const readDetails =
|
||||
|
|
|
|||
Loading…
Reference in a new issue