perf(main): reduce runtime launch metadata work

This commit is contained in:
777genius 2026-05-30 21:52:36 +03:00
parent 9f8fc6895a
commit e7d7b3014e
4 changed files with 150 additions and 19 deletions

View file

@ -599,6 +599,15 @@ interface PersistedRuntimeMemberLike {
runtimeSessionId?: string;
}
interface PersistedTeamConfigCacheEntry {
path: string;
size: number;
mtimeMs: number;
ctimeMs: number;
projectPath: string | null;
members: PersistedRuntimeMemberLike[];
}
type RelayInboxMessage = InboxMessage & { messageId: string };
interface RelayInboxMessageView {
@ -3472,6 +3481,7 @@ export class TeamProvisioningService {
stats: RuntimeProcessUsageStats | null;
}
>();
private readonly persistedTeamConfigCache = new Map<string, PersistedTeamConfigCacheEntry>();
private readonly agentRuntimeSnapshotInFlightByTeam = new Map<
string,
{
@ -3764,6 +3774,7 @@ export class TeamProvisioningService {
this.liveTeamAgentRuntimeMetadataCache.delete(teamName);
this.liveTeamAgentRuntimeMetadataInFlightByTeam.delete(teamName);
this.runtimeProcessRowsForUsageSnapshotByTeam.delete(teamName);
this.persistedTeamConfigCache.delete(teamName);
// CPU/RSS samples are TTL-bound and do not decide liveness; keeping them
// avoids repeated pidusage forks when launch-state churn invalidates snapshots.
}
@ -31581,32 +31592,74 @@ export class TeamProvisioningService {
}
}
private readPersistedTeamProjectPath(teamName: string): string | null {
private clonePersistedRuntimeMember(
member: PersistedRuntimeMemberLike
): PersistedRuntimeMemberLike {
return { ...member };
}
private isPersistedRuntimeMemberLike(member: unknown): member is PersistedRuntimeMemberLike {
return !!member && typeof member === 'object';
}
private readPersistedTeamConfig(teamName: string): PersistedTeamConfigCacheEntry | null {
const configPath = path.join(getTeamsBasePath(), teamName, 'config.json');
let stat: fs.Stats;
try {
stat = fs.statSync(configPath);
} catch {
this.persistedTeamConfigCache.delete(teamName);
return null;
}
const cached = this.persistedTeamConfigCache.get(teamName);
if (
cached &&
cached.path === configPath &&
cached.size === stat.size &&
cached.mtimeMs === stat.mtimeMs &&
cached.ctimeMs === stat.ctimeMs
) {
return cached;
}
try {
const raw = fs.readFileSync(configPath, 'utf8');
const parsed = JSON.parse(raw) as { projectPath?: unknown };
const parsed = JSON.parse(raw) as { projectPath?: unknown; members?: unknown };
const projectPath = typeof parsed.projectPath === 'string' ? parsed.projectPath.trim() : '';
return projectPath || null;
const members = Array.isArray(parsed.members)
? parsed.members
.filter((member): member is PersistedRuntimeMemberLike =>
this.isPersistedRuntimeMemberLike(member)
)
.map((member) => this.clonePersistedRuntimeMember(member))
: [];
const entry: PersistedTeamConfigCacheEntry = {
path: configPath,
size: stat.size,
mtimeMs: stat.mtimeMs,
ctimeMs: stat.ctimeMs,
projectPath: projectPath || null,
members,
};
this.persistedTeamConfigCache.set(teamName, entry);
return entry;
} catch {
this.persistedTeamConfigCache.delete(teamName);
return null;
}
}
private readPersistedTeamProjectPath(teamName: string): string | null {
return this.readPersistedTeamConfig(teamName)?.projectPath ?? null;
}
private readPersistedRuntimeMembers(teamName: string): PersistedRuntimeMemberLike[] {
const configPath = path.join(getTeamsBasePath(), teamName, 'config.json');
try {
const raw = fs.readFileSync(configPath, 'utf8');
const parsed = JSON.parse(raw) as { members?: unknown };
if (!Array.isArray(parsed.members)) {
return [];
}
return parsed.members.filter((member): member is PersistedRuntimeMemberLike => {
return !!member && typeof member === 'object';
});
} catch {
return [];
}
return (
this.readPersistedTeamConfig(teamName)?.members.map((member) =>
this.clonePersistedRuntimeMember(member)
) ?? []
);
}
private listPersistedTeamNames(): string[] {

View file

@ -45,6 +45,8 @@ export interface ResolvedTeamMemberRuntimeLiveness {
const SHELL_COMMAND_NAMES = new Set(['sh', 'bash', 'zsh', 'fish', 'dash', 'login', 'tmux']);
const SECRET_FLAG_PATTERN =
/(--(?:api-key|token|password|secret|authorization|auth-token)(?:=|\s+))("[^"]*"|'[^']*'|\S+)/gi;
const CLI_ARG_VALUES_CACHE_MAX_COMMANDS = 1_000;
const cliArgValuesCache = new Map<string, Map<string, string[]>>();
function basenameCommand(command: string | undefined): string {
const firstToken = command?.trim().split(/\s+/, 1)[0] ?? '';
@ -69,6 +71,16 @@ function escapeRegexLiteral(value: string): string {
}
export function extractCliArgValues(command: string, argName: string): string[] {
const cachedByArg = cliArgValuesCache.get(command);
const cachedValues = cachedByArg?.get(argName);
if (cachedValues) {
if (cachedByArg) {
cliArgValuesCache.delete(command);
cliArgValuesCache.set(command, cachedByArg);
}
return [...cachedValues];
}
const escapedArg = escapeRegexLiteral(argName);
const pattern = new RegExp(
`(?:^|\\s)${escapedArg}(?:=|\\s+)("([^"]*)"|'([^']*)'|([^\\s]+))`,
@ -80,7 +92,16 @@ export function extractCliArgValues(command: string, argName: string): string[]
const value = (match[2] ?? match[3] ?? match[4] ?? '').trim();
if (value) values.push(value);
}
return values;
const nextByArg = cachedByArg ?? new Map<string, string[]>();
nextByArg.set(argName, values);
cliArgValuesCache.delete(command);
cliArgValuesCache.set(command, nextByArg);
while (cliArgValuesCache.size > CLI_ARG_VALUES_CACHE_MAX_COMMANDS) {
const oldestKey = cliArgValuesCache.keys().next().value;
if (oldestKey === undefined) break;
cliArgValuesCache.delete(oldestKey);
}
return [...values];
}
export function commandArgEquals(

View file

@ -664,6 +664,8 @@ type TeamProvisioningServicePrivateHarness = {
teamName: string,
options?: { allowAnonymousFailure?: boolean; contextMemberNames?: readonly string[] }
) => Promise<{ kind: string; observedAt: string; source?: string; reason?: string } | null>;
readPersistedRuntimeMembers: (teamName: string) => Array<Record<string, unknown>>;
readPersistedTeamProjectPath: (teamName: string) => string | null;
};
function privateHarness(svc: TeamProvisioningService): TeamProvisioningServicePrivateHarness {
@ -881,6 +883,51 @@ describe('TeamProvisioningService', () => {
});
});
describe('persisted team config cache', () => {
it('returns defensive runtime member copies and refreshes when config changes', () => {
const teamName = 'persisted-config-cache-team';
const teamDir = path.join(tempTeamsBase, teamName);
const configPath = path.join(teamDir, 'config.json');
fs.mkdirSync(teamDir, { recursive: true });
fs.writeFileSync(
configPath,
JSON.stringify({
projectPath: '/repo-one',
members: [{ name: 'alice', agentId: 'agent-alice' }],
}),
'utf8'
);
const svc = new TeamProvisioningService();
const internals = privateHarness(svc);
const firstMembers = internals.readPersistedRuntimeMembers(teamName);
firstMembers[0]!.name = 'mutated';
expect(internals.readPersistedRuntimeMembers(teamName)[0]).toMatchObject({
name: 'alice',
agentId: 'agent-alice',
});
expect(internals.readPersistedTeamProjectPath(teamName)).toBe('/repo-one');
fs.writeFileSync(
configPath,
JSON.stringify({
projectPath: '/repo-two',
members: [{ name: 'bob', agentId: 'agent-bob' }],
}),
'utf8'
);
const refreshedAt = new Date(Date.now() + 5_000);
fs.utimesSync(configPath, refreshedAt, refreshedAt);
expect(internals.readPersistedRuntimeMembers(teamName)[0]).toMatchObject({
name: 'bob',
agentId: 'agent-bob',
});
expect(internals.readPersistedTeamProjectPath(teamName)).toBe('/repo-two');
});
});
describe('live lead messages', () => {
it('updates one live message for Codex synthetic text chunks', () => {
const svc = new TeamProvisioningService();

View file

@ -1,9 +1,9 @@
import { describe, expect, it } from 'vitest';
import {
extractCliArgValues,
resolveTeamMemberRuntimeLiveness,
sanitizeProcessCommandForDiagnostics,
} from '@main/services/team/TeamRuntimeLivenessResolver';
import { describe, expect, it } from 'vitest';
const NOW = '2026-04-24T12:00:00.000Z';
@ -238,4 +238,14 @@ describe('resolveTeamMemberRuntimeLiveness', () => {
sanitizeProcessCommandForDiagnostics('node runtime --api-key sk-123 --token=abc --safe ok')
).toBe('node runtime --api-key [redacted] --token=[redacted] --safe ok');
});
it('keeps cached CLI arg extraction immutable for callers', () => {
const command =
'node runtime --team-name demo --agent-id "agent alice" --agent-id agent-bob';
const first = extractCliArgValues(command, '--agent-id');
first.push('mutated');
expect(extractCliArgValues(command, '--agent-id')).toEqual(['agent alice', 'agent-bob']);
expect(extractCliArgValues(command, '--team-name')).toEqual(['demo']);
});
});