Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Haze <hazeone@users.noreply.github.com>
57 lines
1.9 KiB
TypeScript
57 lines
1.9 KiB
TypeScript
export function nextLifecycleEpoch(currentEpoch: number): number {
|
|
return currentEpoch + 1;
|
|
}
|
|
|
|
export function isLifecycleSuperseded(expectedEpoch: number, currentEpoch: number): boolean {
|
|
return expectedEpoch !== currentEpoch;
|
|
}
|
|
|
|
export interface ReconnectAttemptContext {
|
|
scheduledEpoch: number;
|
|
currentEpoch: number;
|
|
shouldReconnect: boolean;
|
|
}
|
|
|
|
export function getReconnectSkipReason(context: ReconnectAttemptContext): string | null {
|
|
if (!context.shouldReconnect) {
|
|
return 'auto-reconnect disabled';
|
|
}
|
|
if (isLifecycleSuperseded(context.scheduledEpoch, context.currentEpoch)) {
|
|
return `stale reconnect callback (scheduledEpoch=${context.scheduledEpoch}, currentEpoch=${context.currentEpoch})`;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export type GatewayLifecycleState = 'stopped' | 'starting' | 'running' | 'error' | 'reconnecting';
|
|
|
|
export interface RestartDeferralContext {
|
|
state: GatewayLifecycleState;
|
|
startLock: boolean;
|
|
}
|
|
|
|
/**
|
|
* Restart requests should not interrupt an in-flight startup/reconnect flow.
|
|
* Doing so can kill a just-spawned process and leave the manager stopped.
|
|
*/
|
|
export function shouldDeferRestart(context: RestartDeferralContext): boolean {
|
|
return context.startLock || context.state === 'starting' || context.state === 'reconnecting';
|
|
}
|
|
|
|
export interface DeferredRestartActionContext extends RestartDeferralContext {
|
|
hasPendingRestart: boolean;
|
|
shouldReconnect: boolean;
|
|
}
|
|
|
|
export type DeferredRestartAction = 'none' | 'wait' | 'drop' | 'execute';
|
|
|
|
/**
|
|
* Decide what to do with a pending deferred restart once lifecycle changes.
|
|
*/
|
|
export function getDeferredRestartAction(context: DeferredRestartActionContext): DeferredRestartAction {
|
|
if (!context.hasPendingRestart) return 'none';
|
|
if (shouldDeferRestart(context)) return 'wait';
|
|
if (!context.shouldReconnect) return 'drop';
|
|
if (context.state === 'running') return 'drop';
|
|
return 'execute';
|
|
}
|