perf: skip unverifiable runtime process scans
This commit is contained in:
parent
9be096f864
commit
f0514a7d17
2 changed files with 88 additions and 24 deletions
|
|
@ -3719,6 +3719,7 @@ export class TeamProvisioningService {
|
||||||
this.liveTeamAgentRuntimeMetadataCache.delete(teamName);
|
this.liveTeamAgentRuntimeMetadataCache.delete(teamName);
|
||||||
this.liveTeamAgentRuntimeMetadataInFlightByTeam.delete(teamName);
|
this.liveTeamAgentRuntimeMetadataInFlightByTeam.delete(teamName);
|
||||||
this.runtimeProcessRowsForUsageSnapshotByTeam.delete(teamName);
|
this.runtimeProcessRowsForUsageSnapshotByTeam.delete(teamName);
|
||||||
|
this.runtimeProcessUsageStatsCacheByPid.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private cloneMemberSpawnStatusesSnapshot(
|
private cloneMemberSpawnStatusesSnapshot(
|
||||||
|
|
@ -25329,23 +25330,30 @@ export class TeamProvisioningService {
|
||||||
|
|
||||||
let processRows: RuntimeTelemetryProcessTableRow[] = [];
|
let processRows: RuntimeTelemetryProcessTableRow[] = [];
|
||||||
let processTableAvailable = true;
|
let processTableAvailable = true;
|
||||||
try {
|
const shouldReadProcessTable = this.shouldReadProcessTableForLiveRuntimeMetadata({
|
||||||
processRows =
|
metadataByMember,
|
||||||
this.normalizeRuntimeProcessRowsForTelemetry(
|
launchSnapshot: persistedLaunchSnapshot,
|
||||||
await this.withRuntimeTelemetryTimeout(
|
paneInfoById,
|
||||||
listRuntimeProcessTableForCurrentPlatform(),
|
});
|
||||||
TeamProvisioningService.RUNTIME_PROCESS_TABLE_TIMEOUT_MS,
|
if (shouldReadProcessTable) {
|
||||||
'process table runtime snapshot'
|
try {
|
||||||
),
|
processRows =
|
||||||
process.platform === 'win32' ? 'wsl' : 'native'
|
this.normalizeRuntimeProcessRowsForTelemetry(
|
||||||
) ?? [];
|
await this.withRuntimeTelemetryTimeout(
|
||||||
} catch (error) {
|
listRuntimeProcessTableForCurrentPlatform(),
|
||||||
processTableAvailable = false;
|
TeamProvisioningService.RUNTIME_PROCESS_TABLE_TIMEOUT_MS,
|
||||||
logger.debug(
|
'process table runtime snapshot'
|
||||||
`[${teamName}] Failed to read process table for runtime snapshot: ${
|
),
|
||||||
error instanceof Error ? error.message : String(error)
|
process.platform === 'win32' ? 'wsl' : 'native'
|
||||||
}`
|
) ?? [];
|
||||||
);
|
} catch (error) {
|
||||||
|
processTableAvailable = false;
|
||||||
|
logger.debug(
|
||||||
|
`[${teamName}] Failed to read process table for runtime snapshot: ${
|
||||||
|
error instanceof Error ? error.message : String(error)
|
||||||
|
}`
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.runtimeProcessRowsForUsageSnapshotByTeam.set(teamName, {
|
this.runtimeProcessRowsForUsageSnapshotByTeam.set(teamName, {
|
||||||
expiresAtMs: Date.now() + this.getAgentRuntimeSnapshotCacheTtlMs(teamName, runId),
|
expiresAtMs: Date.now() + this.getAgentRuntimeSnapshotCacheTtlMs(teamName, runId),
|
||||||
|
|
@ -25746,6 +25754,34 @@ export class TeamProvisioningService {
|
||||||
return normalizedRows;
|
return normalizedRows;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private shouldReadProcessTableForLiveRuntimeMetadata(params: {
|
||||||
|
metadataByMember: ReadonlyMap<string, LiveTeamAgentRuntimeMetadata>;
|
||||||
|
launchSnapshot: PersistedTeamLaunchSnapshot | null | undefined;
|
||||||
|
paneInfoById: ReadonlyMap<string, TmuxPaneRuntimeInfo>;
|
||||||
|
}): boolean {
|
||||||
|
for (const [memberName, metadata] of params.metadataByMember.entries()) {
|
||||||
|
if (metadata.agentId?.trim()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const paneId = metadata.tmuxPaneId?.trim() ?? '';
|
||||||
|
if (paneId && params.paneInfoById.has(paneId)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const launchRuntimePid = params.launchSnapshot?.members[memberName]?.runtimePid;
|
||||||
|
if (
|
||||||
|
(typeof metadata.metricsPid === 'number' &&
|
||||||
|
Number.isFinite(metadata.metricsPid) &&
|
||||||
|
metadata.metricsPid > 0) ||
|
||||||
|
(typeof launchRuntimePid === 'number' &&
|
||||||
|
Number.isFinite(launchRuntimePid) &&
|
||||||
|
launchRuntimePid > 0)
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private async readRuntimeProcessRowsForUsageSnapshot(
|
private async readRuntimeProcessRowsForUsageSnapshot(
|
||||||
teamName: string,
|
teamName: string,
|
||||||
options: { includeWindowsHostRows?: boolean } = {}
|
options: { includeWindowsHostRows?: boolean } = {}
|
||||||
|
|
|
||||||
|
|
@ -3335,7 +3335,7 @@ describe('TeamProvisioningService', () => {
|
||||||
getConfig: vi.fn(async () => ({
|
getConfig: vi.fn(async () => ({
|
||||||
members: [
|
members: [
|
||||||
{ name: 'team-lead', agentType: 'team-lead' },
|
{ name: 'team-lead', agentType: 'team-lead' },
|
||||||
{ name: 'alice', model: 'gpt-5.4-mini' },
|
{ name: 'alice', model: 'gpt-5.4-mini', agentId: 'alice@runtime-team' },
|
||||||
],
|
],
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
|
|
@ -3363,7 +3363,7 @@ describe('TeamProvisioningService', () => {
|
||||||
getConfig: vi.fn(async () => ({
|
getConfig: vi.fn(async () => ({
|
||||||
members: [
|
members: [
|
||||||
{ name: 'team-lead', agentType: 'team-lead' },
|
{ name: 'team-lead', agentType: 'team-lead' },
|
||||||
{ name: 'alice', model: 'gpt-5.4-mini' },
|
{ name: 'alice', model: 'gpt-5.4-mini', agentId: 'alice@runtime-team' },
|
||||||
],
|
],
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
|
|
@ -3385,6 +3385,26 @@ describe('TeamProvisioningService', () => {
|
||||||
expect(listRuntimeProcessTableForCurrentPlatform).toHaveBeenCalledTimes(1);
|
expect(listRuntimeProcessTableForCurrentPlatform).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('skips live process table reads when runtime metadata has no verifiable handle', async () => {
|
||||||
|
const svc = new TeamProvisioningService();
|
||||||
|
(svc as any).configReader = {
|
||||||
|
getConfig: vi.fn(async () => ({
|
||||||
|
members: [
|
||||||
|
{ name: 'team-lead', agentType: 'team-lead' },
|
||||||
|
{ name: 'alice', model: 'gpt-5.4-mini' },
|
||||||
|
],
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
|
||||||
|
const metadata = (await (svc as any).getLiveTeamAgentRuntimeMetadata('runtime-team')) as Map<
|
||||||
|
string,
|
||||||
|
unknown
|
||||||
|
>;
|
||||||
|
|
||||||
|
expect(metadata.has('alice')).toBe(true);
|
||||||
|
expect(listRuntimeProcessTableForCurrentPlatform).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
it('uses a longer live runtime metadata cache for persisted teams without a tracked run', async () => {
|
it('uses a longer live runtime metadata cache for persisted teams without a tracked run', async () => {
|
||||||
vi.useFakeTimers();
|
vi.useFakeTimers();
|
||||||
vi.setSystemTime(new Date('2026-05-03T12:00:00.000Z'));
|
vi.setSystemTime(new Date('2026-05-03T12:00:00.000Z'));
|
||||||
|
|
@ -3393,7 +3413,7 @@ describe('TeamProvisioningService', () => {
|
||||||
getConfig: vi.fn(async () => ({
|
getConfig: vi.fn(async () => ({
|
||||||
members: [
|
members: [
|
||||||
{ name: 'team-lead', agentType: 'team-lead' },
|
{ name: 'team-lead', agentType: 'team-lead' },
|
||||||
{ name: 'alice', model: 'gpt-5.4-mini' },
|
{ name: 'alice', model: 'gpt-5.4-mini', agentId: 'alice@runtime-team' },
|
||||||
],
|
],
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
|
|
@ -3421,7 +3441,7 @@ describe('TeamProvisioningService', () => {
|
||||||
getConfig: vi.fn(async () => ({
|
getConfig: vi.fn(async () => ({
|
||||||
members: [
|
members: [
|
||||||
{ name: 'team-lead', agentType: 'team-lead' },
|
{ name: 'team-lead', agentType: 'team-lead' },
|
||||||
{ name: 'alice', model: 'gpt-5.4-mini' },
|
{ name: 'alice', model: 'gpt-5.4-mini', agentId: 'alice@runtime-team' },
|
||||||
],
|
],
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
|
|
@ -3441,7 +3461,7 @@ describe('TeamProvisioningService', () => {
|
||||||
getConfig: vi.fn(async () => ({
|
getConfig: vi.fn(async () => ({
|
||||||
members: [
|
members: [
|
||||||
{ name: 'team-lead', agentType: 'team-lead' },
|
{ name: 'team-lead', agentType: 'team-lead' },
|
||||||
{ name: 'alice', model: 'gpt-5.4-mini' },
|
{ name: 'alice', model: 'gpt-5.4-mini', agentId: 'alice@runtime-team' },
|
||||||
],
|
],
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
|
|
@ -3462,7 +3482,12 @@ describe('TeamProvisioningService', () => {
|
||||||
getConfig: vi.fn(async () => ({
|
getConfig: vi.fn(async () => ({
|
||||||
members: [
|
members: [
|
||||||
{ name: 'team-lead', agentType: 'team-lead' },
|
{ name: 'team-lead', agentType: 'team-lead' },
|
||||||
{ name: 'alice', providerId: 'opencode', model: 'gpt-5.4-mini' },
|
{
|
||||||
|
name: 'alice',
|
||||||
|
providerId: 'opencode',
|
||||||
|
model: 'gpt-5.4-mini',
|
||||||
|
agentId: 'alice@runtime-team',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
|
|
@ -4532,7 +4557,10 @@ describe('TeamProvisioningService', () => {
|
||||||
(TeamProvisioningService as any).RUNTIME_PROCESS_TABLE_TIMEOUT_MS = 5;
|
(TeamProvisioningService as any).RUNTIME_PROCESS_TABLE_TIMEOUT_MS = 5;
|
||||||
(svc as any).configReader = {
|
(svc as any).configReader = {
|
||||||
getConfig: vi.fn(async () => ({
|
getConfig: vi.fn(async () => ({
|
||||||
members: [{ name: 'team-lead', agentType: 'team-lead' }],
|
members: [
|
||||||
|
{ name: 'team-lead', agentType: 'team-lead' },
|
||||||
|
{ name: 'alice', model: 'gpt-5.4-mini', agentId: 'alice@runtime-team' },
|
||||||
|
],
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
(svc as any).aliveRunByTeam.set('runtime-team', 'run-1');
|
(svc as any).aliveRunByTeam.set('runtime-team', 'run-1');
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue