mirror of
https://github.com/stablyai/orca.git
synced 2026-10-28 00:02:54 +00:00
fix(codex): preserve delayed session publication passes
This commit is contained in:
@@ -270,6 +270,12 @@ export class CodexRuntimeHomeService {
|
||||
)
|
||||
}
|
||||
|
||||
prepareHostSystemDefaultSessionMigrationPass(): void {
|
||||
invalidateCodexSessionBackfillMarker(
|
||||
join(getCodexSessionBackfillStateDirPath(), 'backfill-complete.json')
|
||||
)
|
||||
}
|
||||
|
||||
// Why: with the real-home flag ON, a managed HOST account runs against its own
|
||||
// self-contained CODEX_HOME (codex-accounts/<id>/home) instead of the shared
|
||||
// runtime mirror. Its auth.json lives there and codex refreshes it in place,
|
||||
@@ -441,9 +447,7 @@ export class CodexRuntimeHomeService {
|
||||
) {
|
||||
return false
|
||||
}
|
||||
invalidateCodexSessionBackfillMarker(
|
||||
join(getCodexSessionBackfillStateDirPath(), 'backfill-complete.json')
|
||||
)
|
||||
this.prepareHostSystemDefaultSessionMigrationPass()
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -8,12 +8,14 @@ describe('createCodexSessionMigrationScheduler', () => {
|
||||
|
||||
it('runs after a managed-account startup switches to host system default', async () => {
|
||||
let eligible = false
|
||||
const prepareScheduledRun = vi.fn()
|
||||
const startBackfill = vi.fn().mockResolvedValue(null)
|
||||
const startIndexHeal = vi.fn().mockResolvedValue(null)
|
||||
const scheduler = createCodexSessionMigrationScheduler({
|
||||
isEligible: () => eligible,
|
||||
isQuitting: () => false,
|
||||
resolveSystemCodexHomePathOverride: () => undefined,
|
||||
prepareScheduledRun,
|
||||
startBackfill,
|
||||
startIndexHeal
|
||||
})
|
||||
@@ -26,15 +28,18 @@ describe('createCodexSessionMigrationScheduler', () => {
|
||||
scheduler.requestRun()
|
||||
await vi.waitFor(() => expect(startIndexHeal).toHaveBeenCalledOnce())
|
||||
expect(startBackfill).toHaveBeenCalledOnce()
|
||||
expect(prepareScheduledRun).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('schedules a delayed rerun after a shared-home launch', async () => {
|
||||
const prepareScheduledRun = vi.fn()
|
||||
const startBackfill = vi.fn().mockResolvedValue(null)
|
||||
const startIndexHeal = vi.fn().mockResolvedValue(null)
|
||||
const scheduler = createCodexSessionMigrationScheduler({
|
||||
isEligible: () => true,
|
||||
isQuitting: () => false,
|
||||
resolveSystemCodexHomePathOverride: () => undefined,
|
||||
prepareScheduledRun,
|
||||
startBackfill,
|
||||
startIndexHeal,
|
||||
initialDelayMs: 1_000
|
||||
@@ -48,15 +53,18 @@ describe('createCodexSessionMigrationScheduler', () => {
|
||||
await vi.advanceTimersByTimeAsync(1)
|
||||
await vi.waitFor(() => expect(startIndexHeal).toHaveBeenCalledOnce())
|
||||
expect(startBackfill).toHaveBeenCalledOnce()
|
||||
expect(prepareScheduledRun).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
it('delays the startup run from the latest shared-home launch', async () => {
|
||||
const prepareScheduledRun = vi.fn()
|
||||
const startBackfill = vi.fn().mockResolvedValue(null)
|
||||
const startIndexHeal = vi.fn().mockResolvedValue(null)
|
||||
const scheduler = createCodexSessionMigrationScheduler({
|
||||
isEligible: () => true,
|
||||
isQuitting: () => false,
|
||||
resolveSystemCodexHomePathOverride: () => undefined,
|
||||
prepareScheduledRun,
|
||||
startBackfill,
|
||||
startIndexHeal,
|
||||
initialDelayMs: 1_000
|
||||
@@ -72,10 +80,12 @@ describe('createCodexSessionMigrationScheduler', () => {
|
||||
await vi.advanceTimersByTimeAsync(999)
|
||||
await vi.waitFor(() => expect(startIndexHeal).toHaveBeenCalledOnce())
|
||||
expect(startBackfill).toHaveBeenCalledOnce()
|
||||
expect(prepareScheduledRun).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
it('preserves a delayed launch rerun while an earlier migration is active', async () => {
|
||||
let releaseFirstIndexHeal: (() => void) | undefined
|
||||
const prepareScheduledRun = vi.fn()
|
||||
const startBackfill = vi.fn().mockResolvedValue(null)
|
||||
const startIndexHeal = vi
|
||||
.fn()
|
||||
@@ -90,6 +100,7 @@ describe('createCodexSessionMigrationScheduler', () => {
|
||||
isEligible: () => true,
|
||||
isQuitting: () => false,
|
||||
resolveSystemCodexHomePathOverride: () => undefined,
|
||||
prepareScheduledRun,
|
||||
startBackfill,
|
||||
startIndexHeal,
|
||||
initialDelayMs: 1_000
|
||||
@@ -101,10 +112,60 @@ describe('createCodexSessionMigrationScheduler', () => {
|
||||
scheduler.scheduleRun()
|
||||
await vi.advanceTimersByTimeAsync(1_000)
|
||||
expect(startBackfill).toHaveBeenCalledOnce()
|
||||
expect(prepareScheduledRun).not.toHaveBeenCalled()
|
||||
|
||||
releaseFirstIndexHeal?.()
|
||||
await vi.waitFor(() => expect(startBackfill).toHaveBeenCalledTimes(2))
|
||||
await vi.waitFor(() => expect(startIndexHeal).toHaveBeenCalledTimes(2))
|
||||
expect(prepareScheduledRun).toHaveBeenCalledOnce()
|
||||
expect(prepareScheduledRun.mock.invocationCallOrder[0]).toBeLessThan(
|
||||
startBackfill.mock.invocationCallOrder[1]!
|
||||
)
|
||||
})
|
||||
|
||||
it('prepares a delayed launch pass after an earlier migration settles before the timer', async () => {
|
||||
let releaseFirstBackfill: (() => void) | undefined
|
||||
let markerPresent = false
|
||||
const prepareScheduledRun = vi.fn(() => {
|
||||
markerPresent = false
|
||||
})
|
||||
const startBackfill = vi
|
||||
.fn()
|
||||
.mockImplementationOnce(
|
||||
() =>
|
||||
new Promise<void>((resolve) => {
|
||||
releaseFirstBackfill = () => {
|
||||
markerPresent = true
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
)
|
||||
.mockImplementationOnce(async () => {
|
||||
expect(markerPresent).toBe(false)
|
||||
})
|
||||
const startIndexHeal = vi.fn().mockResolvedValue(null)
|
||||
const scheduler = createCodexSessionMigrationScheduler({
|
||||
isEligible: () => true,
|
||||
isQuitting: () => false,
|
||||
resolveSystemCodexHomePathOverride: () => undefined,
|
||||
prepareScheduledRun,
|
||||
startBackfill,
|
||||
startIndexHeal,
|
||||
initialDelayMs: 1_000
|
||||
})
|
||||
|
||||
scheduler.requestRun()
|
||||
scheduler.scheduleRun()
|
||||
releaseFirstBackfill?.()
|
||||
await Promise.resolve()
|
||||
await Promise.resolve()
|
||||
await Promise.resolve()
|
||||
expect(markerPresent).toBe(true)
|
||||
expect(startIndexHeal).toHaveBeenCalledOnce()
|
||||
|
||||
await vi.advanceTimersByTimeAsync(1_000)
|
||||
await vi.waitFor(() => expect(startBackfill).toHaveBeenCalledTimes(2))
|
||||
expect(prepareScheduledRun).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
it('coalesces concurrent run requests and stops before index heal after opt-out', async () => {
|
||||
|
||||
@@ -15,16 +15,25 @@ export function createCodexSessionMigrationScheduler(args: {
|
||||
isEligible: () => boolean
|
||||
isQuitting: () => boolean
|
||||
resolveSystemCodexHomePathOverride: () => string | undefined
|
||||
prepareScheduledRun?: () => void
|
||||
startBackfill: MigrationRun
|
||||
startIndexHeal: MigrationRun
|
||||
initialDelayMs?: number
|
||||
}): CodexSessionMigrationScheduler {
|
||||
let scheduledTimer: ReturnType<typeof setTimeout> | null = null
|
||||
let scheduledRunGeneration = 0
|
||||
let pendingScheduledRunGeneration: number | null = null
|
||||
let migrationTask: Promise<void> | null = null
|
||||
let activeRunStopObserved = false
|
||||
let rerunRequested = false
|
||||
|
||||
const requestRun = (rerunIfActive = false): void => {
|
||||
const requestRun = (rerunIfActive = false, requestedGeneration?: number): void => {
|
||||
if (requestedGeneration !== undefined) {
|
||||
pendingScheduledRunGeneration = Math.max(
|
||||
requestedGeneration,
|
||||
pendingScheduledRunGeneration ?? requestedGeneration
|
||||
)
|
||||
}
|
||||
if (args.isQuitting() || !args.isEligible()) {
|
||||
return
|
||||
}
|
||||
@@ -33,6 +42,11 @@ export function createCodexSessionMigrationScheduler(args: {
|
||||
rerunRequested ||= rerunIfActive || activeRunStopObserved
|
||||
return
|
||||
}
|
||||
if (pendingScheduledRunGeneration !== null) {
|
||||
pendingScheduledRunGeneration = null
|
||||
// Why: an older active pass can rewrite the marker after launch invalidates it.
|
||||
args.prepareScheduledRun?.()
|
||||
}
|
||||
activeRunStopObserved = false
|
||||
rerunRequested = false
|
||||
const shouldStop = (): boolean => {
|
||||
@@ -69,11 +83,11 @@ export function createCodexSessionMigrationScheduler(args: {
|
||||
})
|
||||
}
|
||||
|
||||
const armScheduledRun = (): void => {
|
||||
const armScheduledRun = (generation?: number): void => {
|
||||
scheduledTimer = setTimeout(() => {
|
||||
scheduledTimer = null
|
||||
// Why: a launch can invalidate the marker while a long index-heal pass is active.
|
||||
requestRun(true)
|
||||
requestRun(true, generation)
|
||||
}, args.initialDelayMs ?? 15_000)
|
||||
}
|
||||
|
||||
@@ -88,7 +102,8 @@ export function createCodexSessionMigrationScheduler(args: {
|
||||
if (scheduledTimer) {
|
||||
clearTimeout(scheduledTimer)
|
||||
}
|
||||
armScheduledRun()
|
||||
scheduledRunGeneration += 1
|
||||
armScheduledRun(scheduledRunGeneration)
|
||||
},
|
||||
requestRun: () => requestRun()
|
||||
}
|
||||
|
||||
@@ -2225,6 +2225,7 @@ void app.whenReady().then(async () => {
|
||||
isQuitting: () => isQuitting,
|
||||
resolveSystemCodexHomePathOverride: () =>
|
||||
resolveHostCodexSessionSourceHome(store!.getSettings()),
|
||||
prepareScheduledRun: () => codexRuntimeHome?.prepareHostSystemDefaultSessionMigrationPass(),
|
||||
startBackfill: startCodexSessionBackfillInBackground,
|
||||
startIndexHeal: startCodexSessionIndexHealInBackground
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user