Skip to content

fix: improve the ping code #114

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 9, 2021
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ Name | Description
[netlify-plugin-prebuild-example](https://github.com/cypress-io/netlify-plugin-prebuild-example) | Runs tests twice, first using the development version of the site, then after Netlify builds the production bundles, runs the tests again
[cypress-example-kitchensink](https://github.com/cypress-io/cypress-example-kitchensink) | Runs only a subset of all tests before publishing the folder to Netlify
[bahmutov/eleventyone](https://github.com/bahmutov/eleventyone) | Example used in [Test Sites Deployed To Netlify Using netlify-plugin-cypress](https://glebbahmutov.com/blog/test-netlify/) tutorial
[gatsby-starter-portfolio-cara](https://github.com/bahmutov/gatsby-starter-portfolio-cara) | A Gatsby site example

## Debugging

Expand Down
19 changes: 19 additions & 0 deletions src/ping-cli.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// a little CLI utility for testing pinging websites
// node ./src/ping-cli <url>

const { ping } = require('./utils')
const timeoutSeconds = 60
const url = process.argv[2]
console.log('pinging url %s for %d seconds', url, timeoutSeconds)
if (!url) {
console.error('Missing url to ping')
process.exit(1)
}
ping(url, timeoutSeconds * 1000).then(
() => {
console.log('all good')
},
(err) => {
console.error('a problem', err)
},
)
75 changes: 75 additions & 0 deletions src/ping.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
const got = require('got')
const debug = require('debug')('netlify-plugin-cypress')
const debugVerbose = require('debug')('netlify-plugin-cypress:verbose')

/**
* A small utility for checking when an URL responds, kind of
* a poor man's https://www.npmjs.com/package/wait-on. This version
* is implemented using https://github.com/sindresorhus/got
*/
const ping = (url, timeout) => {
if (!timeout) {
throw new Error('Expected timeout in ms')
}

debug('pinging "%s" for %d ms max', url, timeout)

// make copy of the error codes that "got" retries on
const errorCodes = [...got.defaults.options.retry.errorCodes]
errorCodes.push('ESOCKETTIMEDOUT')

// we expect the server to respond within a time limit
// and if it does not - retry up to total "timeout" duration
const individualPingTimeout = Math.min(timeout, 30000)
const limit = Math.ceil(timeout / individualPingTimeout)

debug(`total ping timeout ${timeout}`)
debug(`individual ping timeout ${individualPingTimeout}ms`)
debug(`retries limit ${limit}`)

const start = +new Date()
return got(url, {
headers: {
Accept: 'text/html, application/json, text/plain, */*',
},
timeout: individualPingTimeout,
errorCodes,
retry: {
limit,
calculateDelay({ error, attemptCount }) {
if (error) {
debugVerbose(`got error ${JSON.stringify(error)}`)
}
const now = +new Date()
const elapsed = now - start
debugVerbose(
`${elapsed}ms ${error.method} ${error.host} ${error.code} attempt ${attemptCount}`,
)
if (elapsed > timeout) {
console.error(
'%s timed out on retry %d of %d',
url,
attemptCount,
limit,
)
return 0
}

// if the error code is ECONNREFUSED use shorter timeout
// because the server is probably starting
if (error.code === 'ECONNREFUSED') {
return 1000
}

// default "long" timeout
return individualPingTimeout
},
},
}).then(() => {
const now = +new Date()
const elapsed = now - start
debug(`pinging ${url} has finished ok after ${elapsed}ms`)
})
}

module.exports = { ping }
40 changes: 1 addition & 39 deletions src/utils.js
Original file line number Diff line number Diff line change
@@ -1,45 +1,7 @@
// @ts-check
const puppeteer = require('puppeteer')
const got = require('got')
const debug = require('debug')('netlify-plugin-cypress')
const debugVerbose = require('debug')('netlify-plugin-cypress:verbose')

/**
* A small utility for checking when an URL responds, kind of
* a poor man's https://www.npmjs.com/package/wait-on
*/
const ping = (url, timeout) => {
debug('pinging "%s" for %d ms max', url, timeout)
const start = +new Date()

return got(url, {
retry: {
limit: 30,
calculateDelay({ attemptCount, retryOptions, error }) {
const now = +new Date()
const elapsed = now - start
debugVerbose(`attempt ${attemptCount} ${elapsed}ms ${error.message}`)

if (elapsed > timeout) {
debug(
'%s timed out after %dms, timeout was %dms',
url,
elapsed,
timeout,
)
console.error(
'%s timed out after %dms, timeout was %dms',
url,
elapsed,
timeout,
)
return 0
}
return 1000
},
},
})
}
const { ping } = require('./ping')

const getBrowserPath = async () => {
const browserFetcher = puppeteer.createBrowserFetcher()
Expand Down
1 change: 1 addition & 0 deletions tests/routing/netlify.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ TERM = "xterm"
[plugins.inputs.preBuild]
start = 'npm start'
wait-on = 'http://localhost:3000'
wait-on-timeout = '45' # seconds

# and test the built site after
[plugins.inputs]
Expand Down