perf: cache persisted spawn status reads
This commit is contained in:
parent
fa242d9ff6
commit
35a9b05637
2 changed files with 52 additions and 2 deletions
|
|
@ -3306,6 +3306,7 @@ export class TeamProvisioningService {
|
|||
private static readonly RUNTIME_PIDUSAGE_SINGLE_TIMEOUT_MS = 750;
|
||||
private static readonly RUNTIME_PIDUSAGE_FALLBACK_CONCURRENCY = 16;
|
||||
private static readonly MEMBER_SPAWN_STATUS_SNAPSHOT_CACHE_TTL_MS = 500;
|
||||
private static readonly PERSISTED_MEMBER_SPAWN_STATUS_SNAPSHOT_CACHE_TTL_MS = 2_000;
|
||||
private static readonly LAUNCH_STATE_NOOP_REFRESH_MS = 15_000;
|
||||
private static readonly RETAINED_PROVISIONING_PROGRESS_TTL_MS = 5 * 60_000;
|
||||
private static readonly OPENCODE_RUNTIME_DELIVERY_ADVISORY_EVENT_TTL_MS = 24 * 60 * 60_000;
|
||||
|
|
@ -3445,7 +3446,7 @@ export class TeamProvisioningService {
|
|||
{
|
||||
expiresAtMs: number;
|
||||
generation: number;
|
||||
runId: string;
|
||||
runId: string | null;
|
||||
snapshot: MemberSpawnStatusesSnapshot;
|
||||
}
|
||||
>();
|
||||
|
|
@ -13821,6 +13822,17 @@ export class TeamProvisioningService {
|
|||
source?: 'live' | 'persisted' | 'merged';
|
||||
}> {
|
||||
const readPersistedStatuses = async (resolvedRunId: string | null) => {
|
||||
const generationAtStart = this.getMemberSpawnStatusesCacheGeneration(teamName);
|
||||
const cached = this.memberSpawnStatusesSnapshotCache.get(teamName);
|
||||
if (
|
||||
cached &&
|
||||
cached.expiresAtMs > Date.now() &&
|
||||
cached.runId === resolvedRunId &&
|
||||
cached.generation === generationAtStart
|
||||
) {
|
||||
return this.cloneMemberSpawnStatusesSnapshot(cached.snapshot);
|
||||
}
|
||||
|
||||
const repairSnapshot = await this.readTaskActivityRepairLaunchSnapshot(teamName);
|
||||
this.repairStaleTaskActivityIntervalsOnce(teamName, repairSnapshot);
|
||||
const { snapshot, statuses } = await this.reconcilePersistedLaunchState(teamName);
|
||||
|
|
@ -13842,7 +13854,7 @@ export class TeamProvisioningService {
|
|||
const summary = expectedMembers
|
||||
? summarizeMemberSpawnStatusRecord(expectedMembers, nextStatuses)
|
||||
: undefined;
|
||||
return {
|
||||
const persistedSnapshot = {
|
||||
statuses: nextStatuses,
|
||||
runId: resolvedRunId,
|
||||
teamLaunchState: summary
|
||||
|
|
@ -13854,6 +13866,20 @@ export class TeamProvisioningService {
|
|||
summary: summary ?? snapshot?.summary,
|
||||
source: 'persisted' as const,
|
||||
};
|
||||
if (
|
||||
this.getMemberSpawnStatusesCacheGeneration(teamName) === generationAtStart &&
|
||||
this.getTrackedRunId(teamName) === resolvedRunId
|
||||
) {
|
||||
this.memberSpawnStatusesSnapshotCache.set(teamName, {
|
||||
expiresAtMs:
|
||||
Date.now() +
|
||||
TeamProvisioningService.PERSISTED_MEMBER_SPAWN_STATUS_SNAPSHOT_CACHE_TTL_MS,
|
||||
generation: generationAtStart,
|
||||
runId: resolvedRunId,
|
||||
snapshot: this.cloneMemberSpawnStatusesSnapshot(persistedSnapshot),
|
||||
});
|
||||
}
|
||||
return persistedSnapshot;
|
||||
};
|
||||
|
||||
const runId = this.getTrackedRunId(teamName);
|
||||
|
|
|
|||
|
|
@ -620,6 +620,12 @@ type TeamProvisioningServicePrivateHarness = {
|
|||
applyProcessBootstrapTransportOverlay: (
|
||||
input: Record<string, unknown>
|
||||
) => Record<string, unknown>;
|
||||
reconcilePersistedLaunchState: (
|
||||
teamName: string
|
||||
) => Promise<{
|
||||
snapshot: null;
|
||||
statuses: Record<string, never>;
|
||||
}>;
|
||||
readProcessUsageStatsByPid: (
|
||||
pids: readonly number[]
|
||||
) => Promise<Map<number, { rssBytes?: number; cpuPercent?: number }>>;
|
||||
|
|
@ -21083,6 +21089,24 @@ describe('TeamProvisioningService', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('caches persisted member spawn statuses between close polling reads', async () => {
|
||||
const teamName = 'zz-unit-persisted-status-cache';
|
||||
const svc = new TeamProvisioningService();
|
||||
const harness = privateHarness(svc);
|
||||
harness.reconcilePersistedLaunchState = vi.fn(async () => ({
|
||||
snapshot: null,
|
||||
statuses: {},
|
||||
}));
|
||||
harness.attachLiveRuntimeMetadataToStatuses = vi.fn(async (_teamName, statuses) => statuses);
|
||||
|
||||
const first = await svc.getMemberSpawnStatuses(teamName);
|
||||
const second = await svc.getMemberSpawnStatuses(teamName);
|
||||
|
||||
expect(first).toEqual(second);
|
||||
expect(harness.reconcilePersistedLaunchState).toHaveBeenCalledTimes(1);
|
||||
expect(harness.attachLiveRuntimeMetadataToStatuses).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('does not heal cleanup-finalized launch failures from stale bootstrap-state confirmation', async () => {
|
||||
allowConsoleLogs();
|
||||
const teamName = 'zz-unit-cleanup-finalized-stale-bootstrap-ignored';
|
||||
|
|
|
|||
Loading…
Reference in a new issue