Upgrade third party plugin (#715)

This commit is contained in:
paisley
2026-03-30 14:46:33 +08:00
committed by GitHub
Unverified
parent 91a86a4a76
commit 47c9560b9e
4 changed files with 84 additions and 59 deletions

View File

@@ -427,6 +427,7 @@ export class GatewayManager extends EventEmitter {
try {
await this.restartInFlight;
this.restartGovernor.recordExecuted();
this.restartController.recordRestartCompleted();
const observability = this.restartGovernor.getObservability();
const props = {
gateway_restart_executed_total: observability.executed_total,
@@ -508,13 +509,6 @@ export class GatewayManager extends EventEmitter {
return;
}
if (process.platform === 'win32') {
logger.warn('[gateway-refresh] mode=reload result=fallback_restart cause=windows');
logger.debug('Windows detected, falling back to Gateway restart for reload');
await this.restart();
return;
}
const connectedForMs = this.status.connectedAt
? Date.now() - this.status.connectedAt
: Number.POSITIVE_INFINITY;
@@ -528,6 +522,15 @@ export class GatewayManager extends EventEmitter {
return;
}
if (process.platform === 'win32') {
// Windows does not support SIGUSR1 for in-process reload.
// Fall back to a full restart. The connectedForMs < 8000 guard above
// already skips unnecessary restarts for recently-started processes.
logger.warn('[gateway-refresh] mode=reload result=fallback_restart cause=windows');
await this.restart();
return;
}
try {
process.kill(this.process.pid, 'SIGUSR1');
logger.info(`Sent SIGUSR1 to Gateway for config reload (pid=${this.process.pid})`);
@@ -785,7 +788,14 @@ export class GatewayManager extends EventEmitter {
this.connectionMonitor.clear();
if (this.status.state === 'running') {
this.setStatus({ state: 'stopped' });
this.scheduleReconnect();
// On Windows, skip reconnect from WS close. The Gateway is a local
// child process; actual crashes are already caught by the process exit
// handler (`onExit`) which calls scheduleReconnect(). Triggering
// reconnect from WS close as well races with the exit handler and can
// cause double start() attempts or port conflicts during TCP TIME_WAIT.
if (process.platform !== 'win32') {
this.scheduleReconnect();
}
}
},
});

View File

@@ -16,6 +16,8 @@ type DeferredRestartContext = RestartDeferralState & {
export class GatewayRestartController {
private deferredRestartPending = false;
private deferredRestartRequestedAt = 0;
private lastRestartCompletedAt = 0;
private restartDebounceTimer: NodeJS.Timeout | null = null;
isRestartDeferred(context: RestartDeferralState): boolean {
@@ -33,6 +35,13 @@ export class GatewayRestartController {
);
}
this.deferredRestartPending = true;
if (this.deferredRestartRequestedAt === 0) {
this.deferredRestartRequestedAt = Date.now();
}
}
recordRestartCompleted(): void {
this.lastRestartCompletedAt = Date.now();
}
flushDeferredRestart(
@@ -55,7 +64,9 @@ export class GatewayRestartController {
return;
}
const requestedAt = this.deferredRestartRequestedAt;
this.deferredRestartPending = false;
this.deferredRestartRequestedAt = 0;
if (action === 'drop') {
logger.info(
`Dropping deferred Gateway restart (${trigger}) because lifecycle already recovered (state=${context.state}, shouldReconnect=${context.shouldReconnect})`,
@@ -63,6 +74,16 @@ export class GatewayRestartController {
return;
}
// If a restart already completed after this deferred request was made,
// the current process is already running with the latest config —
// skip the redundant restart to avoid "just started then restart" loops.
if (requestedAt > 0 && this.lastRestartCompletedAt >= requestedAt) {
logger.info(
`Dropping deferred Gateway restart (${trigger}): a restart already completed after the request (requested=${requestedAt}, completed=${this.lastRestartCompletedAt})`,
);
return;
}
logger.info(`Executing deferred Gateway restart now (${trigger})`);
executeRestart();
}
@@ -87,5 +108,6 @@ export class GatewayRestartController {
resetDeferredRestart(): void {
this.deferredRestartPending = false;
this.deferredRestartRequestedAt = 0;
}
}