fix(cutover): close identity binding races
This commit is contained in:
@@ -14,7 +14,7 @@ import {
|
|||||||
} from 'node:fs/promises';
|
} from 'node:fs/promises';
|
||||||
import { createHash } from 'node:crypto';
|
import { createHash } from 'node:crypto';
|
||||||
import { request } from 'node:http';
|
import { request } from 'node:http';
|
||||||
import { basename, isAbsolute, join, resolve } from 'node:path';
|
import { isAbsolute, join, resolve } from 'node:path';
|
||||||
import { GATEWAY_AUTH_HEADER } from './runtime-config.js';
|
import { GATEWAY_AUTH_HEADER } from './runtime-config.js';
|
||||||
import { PRODUCTION_CUTOVER_ACK } from './canary-runtime.js';
|
import { PRODUCTION_CUTOVER_ACK } from './canary-runtime.js';
|
||||||
|
|
||||||
@@ -197,12 +197,7 @@ function exactKeys(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function commandMatchesArgv(command: string, commandArgv: readonly string[]): boolean {
|
function commandMatchesArgv(command: string, commandArgv: readonly string[]): boolean {
|
||||||
const rendered = commandArgv.join(' ');
|
return commandArgv.join(' ') === command;
|
||||||
if (rendered === command) return true;
|
|
||||||
const executable = commandArgv[0];
|
|
||||||
if (executable === undefined) return false;
|
|
||||||
const args = commandArgv.slice(1);
|
|
||||||
return [basename(executable), ...args].join(' ') === command;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function safeString(value: unknown, label: string): string {
|
function safeString(value: unknown, label: string): string {
|
||||||
@@ -431,12 +426,12 @@ export async function cutover(
|
|||||||
MULTI_SIMADMIN_CUTOVER_ACK: PRODUCTION_CUTOVER_ACK,
|
MULTI_SIMADMIN_CUTOVER_ACK: PRODUCTION_CUTOVER_ACK,
|
||||||
MULTI_SIMADMIN_GATEWAY_TOKEN: gatewayToken,
|
MULTI_SIMADMIN_GATEWAY_TOKEN: gatewayToken,
|
||||||
});
|
});
|
||||||
gatewayCommand = await system.command(gatewayPid);
|
|
||||||
gatewayIdentity = await system.identity(gatewayPid);
|
|
||||||
if (!(await waitForGateway(system, gatewayPid, gatewayToken)))
|
if (!(await waitForGateway(system, gatewayPid, gatewayToken)))
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Production gateway failed authenticated ownership verification on port 8788',
|
'Production gateway failed authenticated ownership verification on port 8788',
|
||||||
);
|
);
|
||||||
|
gatewayCommand = await system.command(gatewayPid);
|
||||||
|
gatewayIdentity = await system.identity(gatewayPid);
|
||||||
await durableState(plan, {
|
await durableState(plan, {
|
||||||
...preparedState(plan),
|
...preparedState(plan),
|
||||||
phase: 'active',
|
phase: 'active',
|
||||||
@@ -450,7 +445,12 @@ export async function cutover(
|
|||||||
try {
|
try {
|
||||||
const actual = await system.command(gatewayPid);
|
const actual = await system.command(gatewayPid);
|
||||||
const identity = await system.identity(gatewayPid);
|
const identity = await system.identity(gatewayPid);
|
||||||
if (actual === gatewayCommand && identity === gatewayIdentity) {
|
if (
|
||||||
|
(gatewayCommand === undefined || actual === gatewayCommand) &&
|
||||||
|
(gatewayIdentity === undefined || identity === gatewayIdentity) &&
|
||||||
|
actual !== '' &&
|
||||||
|
identity !== ''
|
||||||
|
) {
|
||||||
system.signal(gatewayPid, 'SIGTERM');
|
system.signal(gatewayPid, 'SIGTERM');
|
||||||
await system.waitGone(gatewayPid);
|
await system.waitGone(gatewayPid);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user