feat: update codex live runtime and restart flow
This commit is contained in:
@@ -13,7 +13,7 @@ import {
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
||||
export const serverCommandKeys = ['test', 'rel', 'work-server', 'command-runner'] as const;
|
||||
export const serverCommandKeys = ['test', 'rel', 'prod', 'work-server', 'command-runner'] as const;
|
||||
|
||||
export type ServerCommandKey = (typeof serverCommandKeys)[number];
|
||||
|
||||
@@ -135,6 +135,26 @@ const APP_BUILD_INFO_FILE_CANDIDATES = [
|
||||
'/tmp/ai-code-test-app-dist/assets',
|
||||
] as const;
|
||||
|
||||
export async function readAppBuildTimestamp(definition: ServerDefinition, options?: { allowLocal?: boolean }) {
|
||||
const allowLocal = options?.allowLocal ?? false;
|
||||
let latestBuiltAt: string | null = null;
|
||||
|
||||
for (const targetPath of APP_BUILD_INFO_FILE_CANDIDATES) {
|
||||
const candidates = [
|
||||
allowLocal ? await readLocalBuildTimestamp(targetPath) : null,
|
||||
await readContainerBuildTimestamp(definition, targetPath),
|
||||
].filter((value): value is string => Boolean(value));
|
||||
|
||||
for (const candidate of candidates) {
|
||||
if (!latestBuiltAt || candidate > latestBuiltAt) {
|
||||
latestBuiltAt = candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return latestBuiltAt;
|
||||
}
|
||||
|
||||
async function readLocalBuildTimestamp(targetPath: string) {
|
||||
try {
|
||||
const targetStat = await stat(targetPath);
|
||||
@@ -587,6 +607,26 @@ function getServerDefinitions(): ServerDefinition[] {
|
||||
},
|
||||
restartStrategy: 'wait',
|
||||
},
|
||||
{
|
||||
key: 'prod',
|
||||
label: 'PROD',
|
||||
summary: '프로덕션 앱 컨테이너',
|
||||
environment: 'production',
|
||||
publicUrl: normalizeUrl(env.SERVER_COMMAND_PROD_URL),
|
||||
checkUrl: normalizeUrl(env.SERVER_COMMAND_PROD_URL),
|
||||
composeFile: path.join(mainProjectRoot, 'docker-compose.yml'),
|
||||
serviceName: env.SERVER_COMMAND_PROD_SERVICE,
|
||||
containerName: 'ai-code-app-prod',
|
||||
commandScript: resolveCommandScriptPath('restart-prod.sh', [projectRoot, mainProjectRoot, '/workspace/main-project']),
|
||||
commandWorkingDirectory: mainProjectRoot,
|
||||
commandEnvironment: {
|
||||
MAIN_PROJECT_ROOT: mainProjectRoot,
|
||||
SERVER_COMMAND_COMPOSE_FILE: path.join(mainProjectRoot, 'docker-compose.yml'),
|
||||
SERVER_COMMAND_SERVICE: env.SERVER_COMMAND_PROD_SERVICE,
|
||||
SERVER_COMMAND_CONTAINER_NAME: 'ai-code-app-prod',
|
||||
},
|
||||
restartStrategy: 'deferred',
|
||||
},
|
||||
{
|
||||
key: 'work-server',
|
||||
label: 'WORK-SERVER',
|
||||
@@ -1223,21 +1263,39 @@ async function inspectRuntime(definition: ServerDefinition): Promise<RuntimeInsp
|
||||
}
|
||||
|
||||
async function inspectAppContainerBuild(definition: ServerDefinition): Promise<BuildInspectionResult | null> {
|
||||
if (definition.key !== 'test') {
|
||||
if (definition.key !== 'test' && definition.key !== 'prod') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (definition.key === 'prod') {
|
||||
const testDefinition = getServerDefinition('test');
|
||||
const testBuiltAt = await readAppBuildTimestamp(testDefinition, { allowLocal: true });
|
||||
const prodBuiltAt = await readAppBuildTimestamp(definition);
|
||||
const updateAvailable = Boolean(testBuiltAt && (!prodBuiltAt || prodBuiltAt < testBuiltAt));
|
||||
|
||||
return {
|
||||
runningVersion: null,
|
||||
runningBuiltAt: prodBuiltAt,
|
||||
latestVersion: null,
|
||||
latestBuiltAt: testBuiltAt,
|
||||
latestSourceChangeAt: null,
|
||||
latestSourceChangePath: null,
|
||||
buildRequired: false,
|
||||
updateAvailable,
|
||||
updateSummary:
|
||||
updateAvailable && testBuiltAt
|
||||
? `운영 반영 시각이 TEST보다 이전입니다. TEST ${testBuiltAt}, 운영 ${prodBuiltAt ?? '미확인'}`
|
||||
: prodBuiltAt
|
||||
? `운영 반영 기준: ${prodBuiltAt}`
|
||||
: '운영 빌드 시각을 읽지 못했습니다.',
|
||||
};
|
||||
}
|
||||
|
||||
const latestSourceChange = await readLatestAppSourceChange();
|
||||
const latestSourceChangedAt = latestSourceChange?.changedAt ?? null;
|
||||
const builtAt = await readAppBuildTimestamp(definition, { allowLocal: true });
|
||||
|
||||
for (const targetPath of APP_BUILD_INFO_FILE_CANDIDATES) {
|
||||
const builtAt =
|
||||
(await readLocalBuildTimestamp(targetPath)) ?? (await readContainerBuildTimestamp(definition, targetPath));
|
||||
|
||||
if (!builtAt) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (builtAt) {
|
||||
return {
|
||||
runningVersion: null,
|
||||
runningBuiltAt: builtAt,
|
||||
|
||||
Reference in New Issue
Block a user