Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -684,8 +684,8 @@ jobs:
# browser: firefox
- host: macos-latest
browser: webkit
# - host: windows-latest
# browser: chromium
- host: windows-latest
browser: chromium

runs-on: ${{ matrix.settings.host }}

Expand Down
3 changes: 2 additions & 1 deletion e2e/adapters-e2e/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default defineConfig({
},

// Increase global timeout for service worker tests
timeout: 30000,
timeout: process.env.CI ? 120000 : 30000,

projects: [
{
Expand All @@ -44,5 +44,6 @@ export default defineConfig({
port: 3000,
stdout: 'pipe',
reuseExistingServer: !process.env.CI,
timeout: process.env.CI ? 120000 : 30000,
},
});
2 changes: 1 addition & 1 deletion e2e/qwik-cli-e2e/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,4 +205,4 @@ export function log(text: string) {
console.log(yellow('E2E: ' + text));
}

export const DEFAULT_TIMEOUT = 30000;
export const DEFAULT_TIMEOUT = process.env.CI ? 120000 : 30000;
3 changes: 2 additions & 1 deletion e2e/qwik-react-e2e/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default defineConfig({
},

// Increase global timeout for service worker tests
timeout: 30000,
timeout: process.env.CI ? 120000 : 30000,

projects: [
{
Expand All @@ -44,5 +44,6 @@ export default defineConfig({
port: 3000,
stdout: 'pipe',
reuseExistingServer: !process.env.CI,
timeout: process.env.CI ? 120000 : 30000,
},
});
5 changes: 4 additions & 1 deletion packages/qwik-city/src/static/main-thread.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,10 @@ export async function mainThread(sys: System) {
flushQueue();
};

loadStaticRoutes();
loadStaticRoutes().catch((e) => {
console.error('SSG route loading failed', e);
reject(e);
});
} catch (e) {
reject(e);
}
Expand Down
52 changes: 24 additions & 28 deletions packages/qwik-city/src/static/node/node-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { Worker } from 'node:worker_threads';
import { isAbsolute, resolve } from 'node:path';
import { ensureDir } from './node-system';
import { normalizePath } from '../../utils/fs';
import { createSingleThreadWorker } from '../worker-thread';

export async function createNodeMainProcess(sys: System, opts: StaticGenerateOptions) {
const ssgWorkers: StaticGeneratorWorker[] = [];
Expand Down Expand Up @@ -50,34 +49,14 @@ export async function createNodeMainProcess(sys: System, opts: StaticGenerateOpt
sitemapOutFile = resolve(outDir, sitemapOutFile);
}
}

const singleThreadWorker = await createSingleThreadWorker(sys);

const createWorker = (workerIndex: number) => {
if (workerIndex === 0) {
// same thread worker, don't start a new process
const ssgSameThreadWorker: StaticGeneratorWorker = {
activeTasks: 0,
totalTasks: 0,

render: async (staticRoute) => {
ssgSameThreadWorker.activeTasks++;
ssgSameThreadWorker.totalTasks++;
const result = await singleThreadWorker(staticRoute);
ssgSameThreadWorker.activeTasks--;
return result;
},

terminate: async () => {},
};
return ssgSameThreadWorker;
}

const createWorker = () => {
let terminateResolve: (() => void) | null = null;
const mainTasks = new Map<string, WorkerMainTask>();

let workerFilePath: string | URL;
let terminateTimeout: number | null = null;

// Launch the worker using the package's index module, which bootstraps the worker thread.
if (typeof __filename === 'string') {
workerFilePath = __filename;
} else {
Expand All @@ -89,6 +68,7 @@ export async function createNodeMainProcess(sys: System, opts: StaticGenerateOpt
}

const nodeWorker = new Worker(workerFilePath, { workerData: opts });
nodeWorker.unref();

const ssgWorker: StaticGeneratorWorker = {
activeTasks: 0,
Expand Down Expand Up @@ -116,7 +96,9 @@ export async function createNodeMainProcess(sys: System, opts: StaticGenerateOpt
terminateResolve = resolve;
nodeWorker.postMessage(msg);
});
await nodeWorker.terminate();
terminateTimeout = setTimeout(async () => {
await nodeWorker.terminate();
}, 1000) as unknown as number;
},
};

Expand Down Expand Up @@ -146,7 +128,11 @@ export async function createNodeMainProcess(sys: System, opts: StaticGenerateOpt
});

nodeWorker.on('exit', (code) => {
if (code !== 1) {
if (terminateTimeout) {
clearTimeout(terminateTimeout);
terminateTimeout = null;
}
if (code !== 0) {
console.error(`worker exit ${code}`);
}
});
Expand Down Expand Up @@ -200,9 +186,15 @@ export async function createNodeMainProcess(sys: System, opts: StaticGenerateOpt
console.error(e);
}
}
ssgWorkers.length = 0;

await Promise.all(promises);
ssgWorkers.length = 0;

// On Windows, give extra time for all workers to fully exit
// This prevents resource conflicts in back-to-back builds
if (process.platform === 'win32') {
await new Promise((resolve) => setTimeout(resolve, 300));
}
};

if (sitemapOutFile) {
Expand All @@ -214,7 +206,11 @@ export async function createNodeMainProcess(sys: System, opts: StaticGenerateOpt
}

for (let i = 0; i < maxWorkers; i++) {
ssgWorkers.push(createWorker(i));
ssgWorkers.push(createWorker());
// On Windows, add delay between worker creation to avoid resource contention
if (process.platform === 'win32' && i < maxWorkers - 1) {
await new Promise((resolve) => setTimeout(resolve, 100));
}
}

const mainCtx: MainContext = {
Expand Down
3 changes: 3 additions & 0 deletions packages/qwik-city/src/static/node/node-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,8 @@ export async function createNodeWorkerProcess(
) {
parentPort?.on('message', async (msg: WorkerInputMessage) => {
parentPort?.postMessage(await onMessage(msg));
if (msg.type === 'close') {
parentPort?.close();
}
});
}
17 changes: 0 additions & 17 deletions packages/qwik-city/src/static/worker-thread.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,23 +39,6 @@ export async function workerThread(sys: System) {
});
}

export async function createSingleThreadWorker(sys: System) {
const ssgOpts = sys.getOptions();
const pendingPromises = new Set<Promise<any>>();

const opts: StaticGenerateHandlerOptions = {
...ssgOpts,
render: (await import(pathToFileURL(ssgOpts.renderModulePath).href)).default,
qwikCityPlan: (await import(pathToFileURL(ssgOpts.qwikCityPlanModulePath).href)).default,
};

return (staticRoute: StaticRoute) => {
return new Promise<StaticWorkerRenderResult>((resolve) => {
workerRender(sys, opts, staticRoute, pendingPromises, resolve);
});
};
}

async function workerRender(
sys: System,
opts: StaticGenerateHandlerOptions,
Expand Down