补充 dev:all 启动摘要表
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust smoke (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust smoke (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
在 AGC Vite marker 就绪后打印全部服务的实际地址表。 补充 AGC 就绪等待、摘要构造测试和开发运维文档。
This commit is contained in:
+95
-1
@@ -19,6 +19,7 @@ const rootReadyTimeoutMs = 660_000;
|
||||
const rootReadyPollMs = 500;
|
||||
const childGracefulTimeoutMs = 2_500;
|
||||
const childForceTimeoutMs = 2_000;
|
||||
const agcReadyPollMs = 500;
|
||||
|
||||
const rootOnlyOptions = new Set([
|
||||
'--database',
|
||||
@@ -139,6 +140,57 @@ async function areRootFrontendsReady(state) {
|
||||
return results.every(Boolean);
|
||||
}
|
||||
|
||||
async function readAgcFrontendMarker(endpoint, timeoutMs = 1_000) {
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
||||
try {
|
||||
const response = await fetch(endpoint.markerUrl, {
|
||||
signal: controller.signal,
|
||||
});
|
||||
if (!response.ok) {
|
||||
return null;
|
||||
}
|
||||
const marker = await response.json();
|
||||
return marker?.schemaVersion === 1 &&
|
||||
marker?.app === 'ai-game-creator-shell'
|
||||
? marker
|
||||
: null;
|
||||
} catch {
|
||||
return null;
|
||||
} finally {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
}
|
||||
|
||||
async function waitForAgcFrontend(child, endpoint, options = {}) {
|
||||
const timeoutMs = options.timeoutMs ?? rootReadyTimeoutMs;
|
||||
const pollMs = options.pollMs ?? agcReadyPollMs;
|
||||
const readMarker = options.readMarker ?? readAgcFrontendMarker;
|
||||
const childExit = waitForChildExit(child);
|
||||
const startedAt = Date.now();
|
||||
|
||||
while (Date.now() - startedAt < timeoutMs) {
|
||||
if (await readMarker(endpoint)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const result = await Promise.race([
|
||||
childExit,
|
||||
wait(pollMs).then(() => null),
|
||||
]);
|
||||
if (result) {
|
||||
const detail = result.error
|
||||
? result.error.message
|
||||
: result.signal
|
||||
? `signal=${result.signal}`
|
||||
: `code=${result.code ?? 1}`;
|
||||
throw new Error(`AGC Vite 未就绪即退出: ${detail}`);
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`等待 AGC Vite 就绪超时:${endpoint.url}`);
|
||||
}
|
||||
|
||||
function isActiveService(service, expectedRepoRoot, expectedInstanceId) {
|
||||
return Boolean(
|
||||
service &&
|
||||
@@ -201,6 +253,36 @@ function isSharedRootStackReady(
|
||||
);
|
||||
}
|
||||
|
||||
function formatServiceStatus(service) {
|
||||
return service?.status === 'reused' ? '已复用' : '已启动';
|
||||
}
|
||||
|
||||
function buildStartupSummary(state, agcEndpoint) {
|
||||
const services = state?.services ?? {};
|
||||
const rows = [
|
||||
['SpacetimeDB', services.spacetime],
|
||||
['BgFilter worker', services['bgfilter-worker']],
|
||||
['API server', services['api-server']],
|
||||
['Web 主站', services.web],
|
||||
['Admin 后台', services['admin-web']],
|
||||
].map(([name, service]) => ({
|
||||
项目: name,
|
||||
状态: formatServiceStatus(service),
|
||||
地址: service?.url ?? '—',
|
||||
}));
|
||||
|
||||
return [
|
||||
...rows,
|
||||
{ 项目: 'AGC Vite', 状态: '已启动', 地址: agcEndpoint.url },
|
||||
{ 项目: 'Tauri AGC', 状态: '已启动', 地址: '本地窗口' },
|
||||
];
|
||||
}
|
||||
|
||||
function printStartupSummary(state, agcEndpoint, table = console.table) {
|
||||
console.log('\n[dev:all] 全部开发服务已启动');
|
||||
table(buildStartupSummary(state, agcEndpoint));
|
||||
}
|
||||
|
||||
function waitForChildExit(child) {
|
||||
if (!child) {
|
||||
return Promise.resolve({ code: null, signal: null, error: null });
|
||||
@@ -366,6 +448,7 @@ async function runDevAll(argv = process.argv.slice(2), dependencies = {}) {
|
||||
const stopProcessTree = dependencies.stopProcessTree ?? terminateChildTree;
|
||||
const readState = dependencies.readState ?? (() => readDevStackState());
|
||||
const waitForRoot = dependencies.waitForRoot ?? waitForRootStack;
|
||||
const waitForAgc = dependencies.waitForAgc ?? waitForAgcFrontend;
|
||||
|
||||
let rootChild = null;
|
||||
let agcChild = null;
|
||||
@@ -410,7 +493,7 @@ async function runDevAll(argv = process.argv.slice(2), dependencies = {}) {
|
||||
);
|
||||
rootChild = spawnProcess(npmCommand, rootArgs, env);
|
||||
const rootExit = waitForChildExit(rootChild);
|
||||
await waitForRoot(rootChild, {
|
||||
const rootState = await waitForRoot(rootChild, {
|
||||
readState,
|
||||
expected: {
|
||||
expectedRepoRoot: repoRoot,
|
||||
@@ -430,6 +513,16 @@ async function runDevAll(argv = process.argv.slice(2), dependencies = {}) {
|
||||
console.log('[dev:all] 根开发栈已就绪,启动 AGC Vite 与 Tauri');
|
||||
agcChild = spawnProcess(npmCommand, ['run', 'agc'], env);
|
||||
const agcExit = waitForChildExit(agcChild);
|
||||
await waitForAgc(agcChild, endpoint);
|
||||
if (rootChild.exitCode !== null || rootChild.signalCode !== null) {
|
||||
throw new Error('根开发栈在 AGC 就绪前退出');
|
||||
}
|
||||
if (shuttingDown) {
|
||||
await stopAll();
|
||||
return signalExitCode || 1;
|
||||
}
|
||||
|
||||
printStartupSummary(readState() ?? rootState, endpoint);
|
||||
const result = await Promise.race([
|
||||
rootExit.then((exit) => ({ owner: 'root', exit })),
|
||||
agcExit.then((exit) => ({ owner: 'agc', exit })),
|
||||
@@ -469,6 +562,7 @@ export {
|
||||
buildDevAllEnvironment,
|
||||
buildManagedSpawnOptions,
|
||||
buildRootDevArgs,
|
||||
buildStartupSummary,
|
||||
isSharedRootStackReady,
|
||||
readDevStackState,
|
||||
runDevAll,
|
||||
|
||||
Reference in New Issue
Block a user