Files
zn-ai/electron/gateway/process-policy.ts
DEV_DSW 71bcc3b3c5 feat: implement telemetry system for application usage tracking
- Added telemetry utility to capture application events and metrics.
- Integrated PostHog for event tracking with distinct user identification.
- Implemented telemetry initialization, event capturing, and shutdown procedures.

feat: add UV environment setup for Python management

- Created utilities to manage Python installation and configuration.
- Implemented network optimization checks for Python installation mirrors.
- Added functions to set up managed Python environments with error handling.

feat: enhance host API communication with token management

- Introduced host API token retrieval and management for secure requests.
- Updated host API fetch functions to include token in headers.
- Added support for creating event sources with authentication.

test: add comprehensive tests for gateway protocol and startup helpers

- Implemented unit tests for gateway protocol helpers, event dispatching, and state management.
- Added tests for startup recovery strategies and process policies.
- Ensured coverage for connection monitoring and restart governance logic.
2026-04-23 17:21:57 +08:00

108 lines
3.0 KiB
TypeScript

export interface ReconnectConfig {
maxAttempts: number;
baseDelay: number;
maxDelay: number;
}
export const DEFAULT_RECONNECT_CONFIG: ReconnectConfig = {
maxAttempts: 10,
baseDelay: 1000,
maxDelay: 30000,
};
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 interface ReconnectScheduleContext {
shouldReconnect: boolean;
hasReconnectTimer: boolean;
reconnectAttempts: number;
maxAttempts: number;
baseDelay: number;
maxDelay: number;
}
export type ReconnectScheduleDecision =
| { action: 'skip'; reason: string }
| { action: 'already-scheduled' }
| { action: 'fail'; attempts: number; maxAttempts: number }
| { action: 'schedule'; nextAttempt: number; maxAttempts: number; delay: number };
export function getReconnectScheduleDecision(
context: ReconnectScheduleContext,
): ReconnectScheduleDecision {
if (!context.shouldReconnect) {
return { action: 'skip', reason: 'auto-reconnect disabled' };
}
if (context.hasReconnectTimer) {
return { action: 'already-scheduled' };
}
if (context.reconnectAttempts >= context.maxAttempts) {
return {
action: 'fail',
attempts: context.reconnectAttempts,
maxAttempts: context.maxAttempts,
};
}
const delay = Math.min(
context.baseDelay * Math.pow(2, context.reconnectAttempts),
context.maxDelay,
);
return {
action: 'schedule',
nextAttempt: context.reconnectAttempts + 1,
maxAttempts: context.maxAttempts,
delay,
};
}
export type GatewayLifecycleState = 'stopped' | 'starting' | 'running' | 'error' | 'reconnecting';
export interface RestartDeferralContext {
state: GatewayLifecycleState;
startLock: boolean;
}
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';
export function getDeferredRestartAction(context: DeferredRestartActionContext): DeferredRestartAction {
if (!context.hasPendingRestart) return 'none';
if (shouldDeferRestart(context)) return 'wait';
if (!context.shouldReconnect) return 'drop';
return 'execute';
}