mirror of https://github.com/garrytan/gstack.git
Fix browse restart and resilient goto
This commit is contained in:
parent
eca0610e44
commit
7d48890e9b
|
|
@ -500,6 +500,15 @@ async function sendCommand(state: ServerState, command: string, args: string[],
|
||||||
await writeStdout('Server stopped');
|
await writeStdout('Server stopped');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (command === 'restart' && !(await isServerHealthy(state.port))) {
|
||||||
|
const restartEnv: Record<string, string> = {};
|
||||||
|
if (_globalFlags?.proxyUrl) restartEnv.BROWSE_PROXY_URL = _globalFlags.proxyUrl;
|
||||||
|
if (_globalFlags?.headed) restartEnv.BROWSE_HEADED = '1';
|
||||||
|
if (_globalFlags?.configHash) restartEnv.BROWSE_CONFIG_HASH = _globalFlags.configHash;
|
||||||
|
await startServer(Object.keys(restartEnv).length ? restartEnv : undefined);
|
||||||
|
await writeStdout('Server restarted');
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (retries >= 1) throw new Error('[browse] Server crashed twice in a row — aborting');
|
if (retries >= 1) throw new Error('[browse] Server crashed twice in a row — aborting');
|
||||||
console.error('[browse] Server connection lost. Restarting...');
|
console.error('[browse] Server connection lost. Restarting...');
|
||||||
// Kill the old server to avoid orphaned chromium processes
|
// Kill the old server to avoid orphaned chromium processes
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,24 @@ const CLEANUP_SELECTORS = {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
async function withManualTimeout<T>(
|
||||||
|
promise: Promise<T>,
|
||||||
|
timeoutMs: number
|
||||||
|
): Promise<{ timedOut: false; value: T } | { timedOut: true }> {
|
||||||
|
promise.catch(() => {});
|
||||||
|
let timeout: ReturnType<typeof setTimeout> | undefined;
|
||||||
|
try {
|
||||||
|
return await Promise.race([
|
||||||
|
promise.then((value) => ({ timedOut: false as const, value })),
|
||||||
|
new Promise<{ timedOut: true }>((resolve) => {
|
||||||
|
timeout = setTimeout(() => resolve({ timedOut: true }), timeoutMs);
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
} finally {
|
||||||
|
if (timeout) clearTimeout(timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function handleWriteCommand(
|
export async function handleWriteCommand(
|
||||||
command: string,
|
command: string,
|
||||||
args: string[],
|
args: string[],
|
||||||
|
|
@ -148,9 +166,17 @@ export async function handleWriteCommand(
|
||||||
// must not leave stale content that could resurrect on a later context recreation.
|
// must not leave stale content that could resurrect on a later context recreation.
|
||||||
session.clearLoadedHtml();
|
session.clearLoadedHtml();
|
||||||
const normalizedUrl = await validateNavigationUrl(url);
|
const normalizedUrl = await validateNavigationUrl(url);
|
||||||
const response = await page.goto(normalizedUrl, { waitUntil: 'domcontentloaded', timeout: 15000 });
|
const response = await page.goto(normalizedUrl, { waitUntil: 'commit', timeout: 15000 });
|
||||||
|
const domReady = await withManualTimeout(
|
||||||
|
page.waitForLoadState('domcontentloaded', { timeout: 15000 }),
|
||||||
|
16000
|
||||||
|
);
|
||||||
|
if (domReady.timedOut) {
|
||||||
|
await page.evaluate(() => window.stop()).catch(() => {});
|
||||||
|
}
|
||||||
const status = response?.status() || 'unknown';
|
const status = response?.status() || 'unknown';
|
||||||
return `Navigated to ${normalizedUrl} (${status})`;
|
const suffix = domReady.timedOut ? '; domcontentloaded timed out' : '';
|
||||||
|
return `Navigated to ${normalizedUrl} (${status}${suffix})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'back': {
|
case 'back': {
|
||||||
|
|
|
||||||
|
|
@ -332,6 +332,11 @@ describe('cli command dispatch', () => {
|
||||||
expect(cliSource).not.toContain('IS_WINDOWS ? 2 : 1, result.stdout');
|
expect(cliSource).not.toContain('IS_WINDOWS ? 2 : 1, result.stdout');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('restart connection loss starts once instead of resending restart', () => {
|
||||||
|
expect(cliSource).toContain("if (command === 'restart' && !(await isServerHealthy(state.port)))");
|
||||||
|
expect(cliSource).toContain("await writeStdout('Server restarted')");
|
||||||
|
});
|
||||||
|
|
||||||
test('default headless cold-start does not print a delayed startup banner', () => {
|
test('default headless cold-start does not print a delayed startup banner', () => {
|
||||||
expect(cliSource).not.toContain("console.error('[browse] Starting server...')");
|
expect(cliSource).not.toContain("console.error('[browse] Starting server...')");
|
||||||
expect(cliSource).toContain('Starting server in headed mode');
|
expect(cliSource).toContain('Starting server in headed mode');
|
||||||
|
|
@ -339,6 +344,16 @@ describe('cli command dispatch', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('write command dispatch', () => {
|
||||||
|
const writeSource = fs.readFileSync(path.resolve(__dirname, '../src/write-commands.ts'), 'utf-8');
|
||||||
|
|
||||||
|
test('goto commits first and bounds domcontentloaded wait', () => {
|
||||||
|
expect(writeSource).toContain("page.goto(normalizedUrl, { waitUntil: 'commit', timeout: 15000 })");
|
||||||
|
expect(writeSource).toContain("page.waitForLoadState('domcontentloaded', { timeout: 15000 })");
|
||||||
|
expect(writeSource).toContain("await page.evaluate(() => window.stop()).catch(() => {})");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('resolveGstackHome', () => {
|
describe('resolveGstackHome', () => {
|
||||||
test('honors GSTACK_HOME env var when set', () => {
|
test('honors GSTACK_HOME env var when set', () => {
|
||||||
const orig = process.env.GSTACK_HOME;
|
const orig = process.env.GSTACK_HOME;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue