Skip to content

Commit

Permalink
chore(webkit): suppress ECONNRESET...
Browse files Browse the repository at this point in the history
  • Loading branch information
flotwig committed Sep 7, 2022
1 parent b5ba6d7 commit d29b5c6
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 22 deletions.
2 changes: 1 addition & 1 deletion packages/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ if (process.env.CY_NET_PROFILE && isRunningElectron) {
process.stdout.write(`Network profiler writing to ${netProfiler.logPath}\n`)
}

require('./lib/unhandled_exceptions')
require('./lib/unhandled_exceptions').handle()

process.env.UV_THREADPOOL_SIZE = 128

Expand Down
48 changes: 36 additions & 12 deletions packages/server/lib/browsers/webkit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type playwright from 'playwright-webkit'
import type { Browser, BrowserInstance } from './types'
import type { Automation } from '../automation'
import { WebKitAutomation } from './webkit-automation'
import * as unhandledExceptions from '../unhandled_exceptions'
import type { BrowserLaunchOpts, BrowserNewTabOpts } from '@packages/types'
import utils from './utils'

Expand All @@ -28,7 +29,26 @@ export function connectToExisting () {
throw new Error('Cypress-in-Cypress is not supported for WebKit.')
}

/**
* Playwright adds an `exit` event listener to run a cleanup process. It tries to use the current binary to run a Node script by passing it as argv[1].
* However, the Electron binary does not support an entrypoint, leading Cypress to think it's being opened in global mode (no args) when this fn is called.
* Solution is to filter out the problematic function.
* TODO(webkit): do we want to run this cleanup script another way?
* @see https://github.com/microsoft/playwright/blob/7e2aec7454f596af452b51a2866e86370291ac8b/packages/playwright-core/src/utils/processLauncher.ts#L191-L203
*/
function removeBadExitListener () {
const killProcessAndCleanup = process.rawListeners('exit').find((fn) => fn.name === 'killProcessAndCleanup')

// @ts-expect-error Electron's Process types override those of @types/node, leading to `exit` not being recognized as an event
if (killProcessAndCleanup) process.removeListener('exit', killProcessAndCleanup)
else debug('did not find killProcessAndCleanup, which may cause interactive mode to unexpectedly open')
}

export async function open (browser: Browser, url: string, options: BrowserLaunchOpts, automation: Automation): Promise<BrowserInstance> {
if (!options.experimentalWebKitSupport) {
throw new Error('WebKit was launched, but the experimental feature was not enabled. Please add `experimentalWebKitSupport: true` to your config file to launch WebKit.')
}

// resolve pw from user's project path
const pwModulePath = require.resolve('playwright-webkit', { paths: [process.cwd()] })
const pw = await import(pwModulePath) as typeof playwright
Expand All @@ -52,18 +72,7 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc

const pwServer = await pw.webkit.launchServer(launchOptions.preferences)

/**
* Playwright adds an `exit` event listener to run a cleanup process. It tries to use the current binary to run a Node script by passing it as argv[1].
* However, the Electron binary does not support an entrypoint, leading Cypress to think it's being opened in global mode (no args) when this fn is called.
* Solution is to filter out the problematic function.
* TODO(webkit): do we want to run this cleanup script another way?
* @see https://github.com/microsoft/playwright/blob/7e2aec7454f596af452b51a2866e86370291ac8b/packages/playwright-core/src/utils/processLauncher.ts#L191-L203
*/
const killProcessAndCleanup = process.rawListeners('exit').find((fn) => fn.name === 'killProcessAndCleanup')

// @ts-expect-error Electron's Process types override those of @types/node, leading to `exit` not being recognized as an event
if (killProcessAndCleanup) process.removeListener('exit', killProcessAndCleanup)
else debug('did not find killProcessAndCleanup, which may cause interactive mode to unexpectedly open')
removeBadExitListener()

const pwBrowser = await pw.webkit.connect(pwServer.wsEndpoint())

Expand All @@ -80,13 +89,28 @@ export async function open (browser: Browser, url: string, options: BrowserLaunc
debug('pwBrowser disconnected')
this.emit('exit')
})

this.suppressUnhandledEconnreset()
}

async kill () {
debug('closing pwBrowser')
await pwBrowser.close()
wkAutomation = undefined
}

/**
* An unhandled `read ECONNRESET` in the depths of `playwright-webkit` is causing the process to crash when running kitchensink on Linux. Absent a
* way to attach to the `error` event, this replaces the global `unhandledException` handler with one that will not exit the process on ECONNRESET.
*/
private suppressUnhandledEconnreset () {
unhandledExceptions.handle((err: NodeJS.ErrnoException) => {
return err.code === 'ECONNRESET'
})

// restore normal exception handling behavior
this.once('exit', () => unhandledExceptions.handle())
}
}

return new WkInstance()
Expand Down
9 changes: 0 additions & 9 deletions packages/server/lib/unhandled_exceptions.js

This file was deleted.

26 changes: 26 additions & 0 deletions packages/server/lib/unhandled_exceptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import Debug from 'debug'
const debug = Debug('cypress:server:unhandled_exceptions')

export function handle (shouldExitCb?: (err: Error) => boolean) {
function globalExceptionHandler (err: Error) {
if (!shouldExitCb?.(err)) {
debug('suppressing unhandled exception, not exiting %o', { err })
handle(shouldExitCb)

return
}

process.exitCode = 1

return require('./errors').logException(err)
.then(() => {
process.exit(1)
})
}

process.removeAllListeners('unhandledRejection')
// @ts-expect-error missing unhandledRejection here
process.once('unhandledRejection', globalExceptionHandler)
process.removeAllListeners('uncaughtException')
process.once('uncaughtException', globalExceptionHandler)
}

0 comments on commit d29b5c6

Please sign in to comment.