mirror of
https://github.com/actions/deploy-pages.git
synced 2026-09-27 05:06:54 +00:00
Validate deployment polling intervals
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -7,6 +7,7 @@ const { MockAgent, setGlobalDispatcher } = require('undici')
|
||||
const {
|
||||
Deployment,
|
||||
MAX_TIMEOUT,
|
||||
DEFAULT_REPORTING_INTERVAL,
|
||||
MAX_REPORTING_INTERVAL,
|
||||
ONE_GIGABYTE,
|
||||
SIZE_LIMIT_DESCRIPTION
|
||||
@@ -614,6 +615,12 @@ describe('Deployment', () => {
|
||||
})
|
||||
|
||||
describe('#check', () => {
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks()
|
||||
delete process.env.INPUT_ERROR_COUNT
|
||||
delete process.env.INPUT_REPORTING_INTERVAL
|
||||
})
|
||||
|
||||
const mockDeploymentStatus = (status, times = 1) => {
|
||||
mockPool
|
||||
.intercept({
|
||||
@@ -1000,7 +1007,7 @@ describe('Deployment', () => {
|
||||
case 'error_count':
|
||||
return 10
|
||||
case 'reporting_interval':
|
||||
return 0 // The default of 5000 is too long for the test
|
||||
return 1 // The default of 5000 is too long for the test
|
||||
case 'timeout':
|
||||
return 42
|
||||
default:
|
||||
@@ -1059,10 +1066,39 @@ describe('Deployment', () => {
|
||||
|
||||
timeoutSpy.mockRestore()
|
||||
randomSpy.mockRestore()
|
||||
delete process.env.INPUT_ERROR_COUNT
|
||||
delete process.env.INPUT_REPORTING_INTERVAL
|
||||
})
|
||||
|
||||
it('does not reduce a configured interval above the backoff cap', async () => {
|
||||
process.env.GITHUB_SHA = 'valid-build-version'
|
||||
process.env.INPUT_ERROR_COUNT = '10'
|
||||
process.env.INPUT_REPORTING_INTERVAL = '45000'
|
||||
mockDeploymentStatus('deployment_in_progress')
|
||||
mockDeploymentStatus('succeed')
|
||||
jest.spyOn(Math, 'random').mockReturnValue(0.5)
|
||||
|
||||
const timeoutSpy = await runWithoutWaiting(createPendingDeployment())
|
||||
|
||||
expect(timeoutSpy.mock.calls.map(([, interval]) => interval)).toEqual([45000, 45000])
|
||||
})
|
||||
|
||||
it.each(['not-a-number', '0', '-1'])(
|
||||
'uses the default reporting interval for invalid input %s',
|
||||
async reportingInterval => {
|
||||
process.env.GITHUB_SHA = 'valid-build-version'
|
||||
process.env.INPUT_ERROR_COUNT = '10'
|
||||
process.env.INPUT_REPORTING_INTERVAL = reportingInterval
|
||||
mockDeploymentStatus('succeed')
|
||||
jest.spyOn(Math, 'random').mockReturnValue(0.5)
|
||||
|
||||
const timeoutSpy = await runWithoutWaiting(createPendingDeployment())
|
||||
|
||||
expect(timeoutSpy).toHaveBeenCalledWith(expect.any(Function), DEFAULT_REPORTING_INTERVAL)
|
||||
expect(core.warning).toHaveBeenCalledWith(
|
||||
`Invalid reporting_interval value; using the default of ${DEFAULT_REPORTING_INTERVAL} milliseconds.`
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
it('jitters status check intervals by up to twenty percent', async () => {
|
||||
process.env.GITHUB_SHA = 'valid-build-version'
|
||||
process.env.INPUT_ERROR_COUNT = '10'
|
||||
@@ -1077,7 +1113,6 @@ describe('Deployment', () => {
|
||||
|
||||
timeoutSpy.mockRestore()
|
||||
randomSpy.mockRestore()
|
||||
delete process.env.INPUT_ERROR_COUNT
|
||||
})
|
||||
|
||||
it('keeps success backoff separate from error backoff', async () => {
|
||||
@@ -1099,7 +1134,6 @@ describe('Deployment', () => {
|
||||
|
||||
timeoutSpy.mockRestore()
|
||||
randomSpy.mockRestore()
|
||||
delete process.env.INPUT_ERROR_COUNT
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ const finalErrorStatus = {
|
||||
}
|
||||
|
||||
const MAX_TIMEOUT = 600000
|
||||
const DEFAULT_REPORTING_INTERVAL = 5000
|
||||
const MAX_REPORTING_INTERVAL = 30000
|
||||
const REPORTING_BACKOFF_MULTIPLIER = 1.5
|
||||
const REPORTING_JITTER_FACTOR = 0.2
|
||||
@@ -146,9 +147,19 @@ class Deployment {
|
||||
}
|
||||
|
||||
const deploymentId = this.deploymentInfo.id || this.buildVersion
|
||||
let reportingInterval = Number(core.getInput('reporting_interval'))
|
||||
const reportingIntervalInput = Number(core.getInput('reporting_interval'))
|
||||
const initialReportingInterval =
|
||||
Number.isFinite(reportingIntervalInput) && reportingIntervalInput > 0
|
||||
? reportingIntervalInput
|
||||
: DEFAULT_REPORTING_INTERVAL
|
||||
const maxReportingInterval = Math.max(MAX_REPORTING_INTERVAL, initialReportingInterval)
|
||||
const maxErrorCount = Number(core.getInput('error_count'))
|
||||
|
||||
if (initialReportingInterval !== reportingIntervalInput) {
|
||||
core.warning(`Invalid reporting_interval value; using the default of ${DEFAULT_REPORTING_INTERVAL} milliseconds.`)
|
||||
}
|
||||
|
||||
let reportingInterval = initialReportingInterval
|
||||
let errorCount = 0
|
||||
|
||||
// Time in milliseconds between two deployment status report when status errored, default 0.
|
||||
@@ -187,10 +198,7 @@ class Deployment {
|
||||
|
||||
// reset the error reporting interval once get the proper status back.
|
||||
errorReportingInterval = 0
|
||||
reportingInterval = Math.min(
|
||||
Math.round(reportingInterval * REPORTING_BACKOFF_MULTIPLIER),
|
||||
MAX_REPORTING_INTERVAL
|
||||
)
|
||||
reportingInterval = Math.min(Math.round(reportingInterval * REPORTING_BACKOFF_MULTIPLIER), maxReportingInterval)
|
||||
} catch (error) {
|
||||
core.error(error.stack)
|
||||
|
||||
@@ -257,6 +265,7 @@ class Deployment {
|
||||
module.exports = {
|
||||
Deployment,
|
||||
MAX_TIMEOUT,
|
||||
DEFAULT_REPORTING_INTERVAL,
|
||||
MAX_REPORTING_INTERVAL,
|
||||
ONE_GIGABYTE,
|
||||
SIZE_LIMIT_DESCRIPTION
|
||||
|
||||
Reference in New Issue
Block a user