fix(ci): address macOS vitest worker crash flakiness

- vitest.config.ts: Use singleFork mode on macOS CI and longer teardown timeout
  to allow proper cleanup of native modules (node:sqlite, chokidar)
- test/setup.ts: Clean up warning filter during test teardown
- src/infra/warnings.ts: Return cleanup function from installProcessWarningFilter
- .github/workflows/ci.yml: Remove retry loop now that root cause is fixed
This commit is contained in:
Andrew Lauppe 2026-01-25 14:39:56 -05:00
parent 1750d0855b
commit 66ef42a2f9
3 changed files with 39 additions and 8 deletions

View File

@ -6,6 +6,11 @@ type Warning = Error & {
message?: string;
};
type WarningFilterState = {
installed: boolean;
listener?: (warning: Warning) => void;
};
function shouldIgnoreWarning(warning: Warning): boolean {
if (warning.code === "DEP0040" && warning.message?.includes("punycode")) {
return true;
@ -22,15 +27,33 @@ function shouldIgnoreWarning(warning: Warning): boolean {
return false;
}
export function installProcessWarningFilter(): void {
/**
* Install a process warning filter that suppresses known benign warnings.
* Returns a cleanup function to remove the listener (useful for test teardown).
*/
export function installProcessWarningFilter(): () => void {
const globalState = globalThis as typeof globalThis & {
[warningFilterKey]?: { installed: boolean };
[warningFilterKey]?: WarningFilterState;
};
if (globalState[warningFilterKey]?.installed) return;
globalState[warningFilterKey] = { installed: true };
if (globalState[warningFilterKey]?.installed) {
// Already installed - return a no-op cleanup
return () => {};
}
process.on("warning", (warning: Warning) => {
const listener = (warning: Warning) => {
if (shouldIgnoreWarning(warning)) return;
process.stderr.write(`${warning.stack ?? warning.toString()}\n`);
});
};
globalState[warningFilterKey] = { installed: true, listener };
process.on("warning", listener);
return () => {
const state = globalState[warningFilterKey];
if (state?.listener) {
process.off("warning", state.listener);
state.listener = undefined;
state.installed = false;
}
};
}

View File

@ -15,10 +15,13 @@ import { setActivePluginRegistry } from "../src/plugins/runtime.js";
import { createTestRegistry } from "../src/test-utils/channel-plugins.js";
import { withIsolatedTestHome } from "./test-env";
installProcessWarningFilter();
const cleanupWarningFilter = installProcessWarningFilter();
const testEnv = withIsolatedTestHome();
afterAll(() => testEnv.cleanup());
afterAll(() => {
testEnv.cleanup();
cleanupWarningFilter();
});
const pickSendFn = (id: ChannelId, deps?: OutboundSendDeps) => {
switch (id) {
case "discord":

View File

@ -11,6 +11,9 @@ const localWorkers = Math.max(4, Math.min(16, os.cpus().length));
// Cap CI workers: Windows/macOS get 2 (flaky worker crashes), Linux gets 3
const ciWorkers = isWindows || isMacOS ? 2 : 3;
// macOS CI needs longer teardown for native module cleanup (sqlite, chokidar)
const macOSCI = isCI && isMacOS;
export default defineConfig({
resolve: {
alias: {
@ -20,6 +23,8 @@ export default defineConfig({
test: {
testTimeout: 120_000,
hookTimeout: isWindows ? 180_000 : 120_000,
// Longer teardown on macOS CI for native module cleanup (node:sqlite, etc.)
teardownTimeout: macOSCI ? 30_000 : 10_000,
pool: "forks",
maxWorkers: isCI ? ciWorkers : localWorkers,
include: [