mirror of
https://github.com/sasjs/adapter.git
synced 2025-12-11 01:14:36 +00:00
feat(poll-strategy): added subsequentStrategies to PollStrategy
This commit is contained in:
@@ -24,20 +24,19 @@ export enum JobState {
|
||||
* @param authConfig - an access token, refresh token, client and secret for an authorized user.
|
||||
* @param pollStrategy - an object containing maxPollCount, pollInterval, streamLog and logFolderPath. It will override the first default poll strategy if provided.
|
||||
* Example:
|
||||
* { maxPollCount: 200, pollInterval: 300, streamLog: false }
|
||||
* @param pollStrategies - an array of poll strategies. It will override default poll strategies if provided.
|
||||
* Example:
|
||||
* {
|
||||
* maxPollCount: 200,
|
||||
* pollInterval: 300,
|
||||
* streamLog: true, // optional, equals to false by default.
|
||||
* subsequentStrategies?: // optional array of the strategies that should be applied after 'maxPollCount' of the provided poll strategy is reached. If not provided the default (see example below) subsequent poll strategies will be used.
|
||||
* }
|
||||
* @param pollStrategies - optional array of poll strategies. It will override default poll strategies if provided.
|
||||
* Example (default poll strategies):
|
||||
* [
|
||||
* { maxPollCount: 200, pollInterval: 300, streamLog: false },
|
||||
* { maxPollCount: 300, pollInterval: 3000, streamLog: false },
|
||||
* { maxPollCount: 500, pollInterval: 30000, streamLog: false }
|
||||
* ]
|
||||
* Default poll strategies:
|
||||
* [
|
||||
* { maxPollCount: 200, pollInterval: 300, streamLog: false }, // INFO: approximately ~2 mins (including time to get response (~300ms))
|
||||
* { maxPollCount: 300, pollInterval: 3000, streamLog: false }, // INFO: approximately ~5.5 mins (including time to get response (~300ms))
|
||||
* { maxPollCount: 400, pollInterval: 30000, streamLog: false }, // INFO: approximately ~50.5 mins (including time to get response (~300ms))
|
||||
* { maxPollCount: 3400, pollInterval: 60000, streamLog: false } // INFO: approximately ~3015 mins (~125 hours) (including time to get response (~300ms))
|
||||
* { maxPollCount: 200, pollInterval: 300 }, // approximately ~2 mins (including time to get response (~300ms))
|
||||
* { maxPollCount: 300, pollInterval: 3000 }, // approximately ~5.5 mins (including time to get response (~300ms))
|
||||
* { maxPollCount: 500, pollInterval: 30000 }, // approximately ~50.5 mins (including time to get response (~300ms))
|
||||
* { maxPollCount: 3400, pollInterval: 60000 } // approximately ~3015 mins (~125 hours) (including time to get response (~300ms))
|
||||
* ]
|
||||
* @returns - a promise which resolves with a job state
|
||||
*/
|
||||
@@ -47,20 +46,42 @@ export async function pollJobState(
|
||||
debug: boolean,
|
||||
authConfig?: AuthConfig,
|
||||
pollStrategy?: PollStrategy,
|
||||
pollStrategies?: PollStrategies
|
||||
streamLog?: boolean
|
||||
): Promise<JobState> {
|
||||
const logger = process.logger || console
|
||||
|
||||
const defaultStreamLog = pollStrategy ? pollStrategy.streamLog : false
|
||||
streamLog = streamLog || false
|
||||
|
||||
const defaultPollStrategies: PollStrategies = [
|
||||
{ maxPollCount: 200, pollInterval: 300, streamLog: defaultStreamLog },
|
||||
{ maxPollCount: 300, pollInterval: 3000, streamLog: defaultStreamLog },
|
||||
{ maxPollCount: 400, pollInterval: 30000, streamLog: defaultStreamLog },
|
||||
{ maxPollCount: 3400, pollInterval: 60000, streamLog: defaultStreamLog }
|
||||
{ maxPollCount: 200, pollInterval: 300 },
|
||||
{ maxPollCount: 400, pollInterval: 30000 },
|
||||
{ maxPollCount: 300, pollInterval: 3000 },
|
||||
{ maxPollCount: 3400, pollInterval: 60000 }
|
||||
]
|
||||
|
||||
if (pollStrategies === undefined) pollStrategies = defaultPollStrategies
|
||||
else validatePollStrategies(pollStrategies)
|
||||
let pollStrategies: PollStrategies
|
||||
|
||||
if (pollStrategy !== undefined) {
|
||||
pollStrategies = [pollStrategy]
|
||||
|
||||
let { subsequentStrategies } = pollStrategy
|
||||
|
||||
if (subsequentStrategies !== undefined) {
|
||||
validatePollStrategies(subsequentStrategies)
|
||||
|
||||
// INFO: sort by 'maxPollCount'
|
||||
subsequentStrategies = subsequentStrategies.sort(
|
||||
(strategyA: PollStrategy, strategyB: PollStrategy) =>
|
||||
strategyA.maxPollCount - strategyB.maxPollCount
|
||||
)
|
||||
|
||||
pollStrategies = [...pollStrategies, ...subsequentStrategies]
|
||||
} else {
|
||||
pollStrategies = [...pollStrategies, ...defaultPollStrategies]
|
||||
}
|
||||
} else {
|
||||
pollStrategies = defaultPollStrategies
|
||||
}
|
||||
|
||||
let defaultPollStrategy: PollStrategy = pollStrategies.splice(0, 1)[0]
|
||||
|
||||
@@ -93,8 +114,9 @@ export async function pollJobState(
|
||||
}
|
||||
|
||||
let logFileStream
|
||||
if (pollStrategy.streamLog && isNode()) {
|
||||
if (streamLog && isNode()) {
|
||||
const { getFileStream } = require('./getFileStream')
|
||||
|
||||
logFileStream = await getFileStream(postedJob, pollStrategy.logFolderPath)
|
||||
}
|
||||
|
||||
@@ -106,6 +128,7 @@ export async function pollJobState(
|
||||
pollCount,
|
||||
pollStrategy,
|
||||
authConfig,
|
||||
streamLog,
|
||||
logFileStream
|
||||
)
|
||||
|
||||
@@ -125,7 +148,6 @@ export async function pollJobState(
|
||||
defaultPollStrategy = pollStrategies.splice(0, 1)[0]
|
||||
|
||||
if (pollStrategy) {
|
||||
defaultPollStrategy.streamLog = pollStrategy.streamLog
|
||||
defaultPollStrategy.logFolderPath = pollStrategy.logFolderPath
|
||||
}
|
||||
|
||||
@@ -137,6 +159,7 @@ export async function pollJobState(
|
||||
pollCount,
|
||||
defaultPollStrategy,
|
||||
authConfig,
|
||||
streamLog,
|
||||
logFileStream
|
||||
)
|
||||
|
||||
@@ -195,6 +218,7 @@ const doPoll = async (
|
||||
pollCount: number,
|
||||
pollStrategy: PollStrategy,
|
||||
authConfig?: AuthConfig,
|
||||
streamLog?: boolean,
|
||||
logStream?: WriteStream
|
||||
): Promise<{ state: JobState; pollCount: number }> => {
|
||||
const { maxPollCount, pollInterval } = pollStrategy
|
||||
@@ -232,7 +256,7 @@ const doPoll = async (
|
||||
|
||||
const jobHref = postedJob.links.find((l: Link) => l.rel === 'self')!.href
|
||||
|
||||
if (pollStrategy?.streamLog) {
|
||||
if (streamLog) {
|
||||
const { result: job } = await requestClient.get<Job>(
|
||||
jobHref,
|
||||
authConfig?.access_token
|
||||
@@ -285,8 +309,6 @@ const validatePollStrategies = (strategies: PollStrategies) => {
|
||||
)
|
||||
}
|
||||
|
||||
if (!strategies.length) throwError('No strategies provided.')
|
||||
|
||||
strategies.forEach((strategy: PollStrategy, i: number) => {
|
||||
const { maxPollCount, pollInterval } = strategy
|
||||
|
||||
|
||||
@@ -15,8 +15,7 @@ const sessionManager = new (<jest.Mock<SessionManager>>SessionManager)()
|
||||
const requestClient = new (<jest.Mock<RequestClient>>RequestClient)()
|
||||
const defaultPollStrategy: PollStrategy = {
|
||||
maxPollCount: 100,
|
||||
pollInterval: 500,
|
||||
streamLog: false
|
||||
pollInterval: 500
|
||||
}
|
||||
|
||||
describe('executeScript', () => {
|
||||
|
||||
@@ -14,10 +14,10 @@ const baseUrl = 'http://localhost'
|
||||
const requestClient = new (<jest.Mock<RequestClient>>RequestClient)()
|
||||
requestClient['httpClient'].defaults.baseURL = baseUrl
|
||||
|
||||
const defaultStreamLog = false
|
||||
const defaultPollStrategy: PollStrategy = {
|
||||
maxPollCount: 100,
|
||||
pollInterval: 500,
|
||||
streamLog: false
|
||||
pollInterval: 500
|
||||
}
|
||||
|
||||
describe('pollJobState', () => {
|
||||
@@ -32,7 +32,8 @@ describe('pollJobState', () => {
|
||||
mockJob,
|
||||
false,
|
||||
mockAuthConfig,
|
||||
defaultPollStrategy
|
||||
defaultPollStrategy,
|
||||
defaultStreamLog
|
||||
)
|
||||
|
||||
expect(getTokensModule.getTokens).toHaveBeenCalledWith(
|
||||
@@ -83,10 +84,14 @@ describe('pollJobState', () => {
|
||||
mockSimplePoll()
|
||||
const { saveLog } = require('../saveLog')
|
||||
|
||||
await pollJobState(requestClient, mockJob, false, mockAuthConfig, {
|
||||
...defaultPollStrategy,
|
||||
streamLog: true
|
||||
})
|
||||
await pollJobState(
|
||||
requestClient,
|
||||
mockJob,
|
||||
false,
|
||||
mockAuthConfig,
|
||||
defaultPollStrategy,
|
||||
true
|
||||
)
|
||||
|
||||
expect(saveLog).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
@@ -96,10 +101,14 @@ describe('pollJobState', () => {
|
||||
const { getFileStream } = require('../getFileStream')
|
||||
const { saveLog } = require('../saveLog')
|
||||
|
||||
await pollJobState(requestClient, mockJob, false, mockAuthConfig, {
|
||||
...defaultPollStrategy,
|
||||
streamLog: true
|
||||
})
|
||||
await pollJobState(
|
||||
requestClient,
|
||||
mockJob,
|
||||
false,
|
||||
mockAuthConfig,
|
||||
defaultPollStrategy,
|
||||
true
|
||||
)
|
||||
|
||||
expect(getFileStream).toHaveBeenCalled()
|
||||
expect(saveLog).toHaveBeenCalledTimes(2)
|
||||
@@ -111,10 +120,14 @@ describe('pollJobState', () => {
|
||||
const { saveLog } = require('../saveLog')
|
||||
const { getFileStream } = require('../getFileStream')
|
||||
|
||||
await pollJobState(requestClient, mockJob, false, mockAuthConfig, {
|
||||
...defaultPollStrategy,
|
||||
streamLog: true
|
||||
})
|
||||
await pollJobState(
|
||||
requestClient,
|
||||
mockJob,
|
||||
false,
|
||||
mockAuthConfig,
|
||||
defaultPollStrategy,
|
||||
true
|
||||
)
|
||||
|
||||
expect(getFileStream).not.toHaveBeenCalled()
|
||||
expect(saveLog).not.toHaveBeenCalled()
|
||||
@@ -137,19 +150,18 @@ describe('pollJobState', () => {
|
||||
it('should return the current status when the max poll count is reached', async () => {
|
||||
mockRunningPoll()
|
||||
|
||||
const pollStrategy = {
|
||||
const pollStrategy: PollStrategy = {
|
||||
...defaultPollStrategy,
|
||||
maxPollCount: 1
|
||||
maxPollCount: 1,
|
||||
subsequentStrategies: []
|
||||
}
|
||||
const pollStrategies = [pollStrategy]
|
||||
|
||||
const state = await pollJobState(
|
||||
requestClient,
|
||||
mockJob,
|
||||
false,
|
||||
mockAuthConfig,
|
||||
pollStrategy,
|
||||
pollStrategies
|
||||
pollStrategy
|
||||
)
|
||||
|
||||
expect(state).toEqual('running')
|
||||
@@ -264,53 +276,32 @@ describe('pollJobState', () => {
|
||||
const pollIntervals = [3, 4, 5, 6]
|
||||
|
||||
const pollStrategies = [
|
||||
{ maxPollCount: 1, pollInterval: pollIntervals[0], streamLog: false },
|
||||
{ maxPollCount: 2, pollInterval: pollIntervals[1], streamLog: false },
|
||||
{ maxPollCount: 3, pollInterval: pollIntervals[2], streamLog: false },
|
||||
{ maxPollCount: 4, pollInterval: pollIntervals[3], streamLog: false }
|
||||
{ maxPollCount: 2, pollInterval: pollIntervals[1] },
|
||||
{ maxPollCount: 3, pollInterval: pollIntervals[2] },
|
||||
{ maxPollCount: 4, pollInterval: pollIntervals[3] }
|
||||
]
|
||||
|
||||
await pollJobState(
|
||||
requestClient,
|
||||
mockJob,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
pollStrategies
|
||||
)
|
||||
const pollStrategy: PollStrategy = {
|
||||
maxPollCount: 1,
|
||||
pollInterval: pollIntervals[0],
|
||||
subsequentStrategies: pollStrategies
|
||||
}
|
||||
|
||||
await pollJobState(requestClient, mockJob, false, undefined, pollStrategy)
|
||||
|
||||
expect(delays).toEqual([pollIntervals[0], ...pollIntervals])
|
||||
})
|
||||
|
||||
it('should throw an error if not valid poll strategies provided', async () => {
|
||||
// INFO: No strategies provided.
|
||||
let expectedError = new Error(
|
||||
'Poll strategies are not valid. No strategies provided.'
|
||||
)
|
||||
|
||||
let pollStrategies: PollStrategies = []
|
||||
|
||||
await expect(
|
||||
pollJobState(
|
||||
requestClient,
|
||||
mockJob,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
pollStrategies
|
||||
)
|
||||
).rejects.toThrow(expectedError)
|
||||
|
||||
// INFO: 'maxPollCount' has to be > 0
|
||||
let invalidPollStrategy = {
|
||||
maxPollCount: 0,
|
||||
pollInterval: 3,
|
||||
streamLog: false
|
||||
pollInterval: 3
|
||||
}
|
||||
|
||||
pollStrategies.push(invalidPollStrategy)
|
||||
let pollStrategies: PollStrategies = [invalidPollStrategy]
|
||||
|
||||
expectedError = new Error(
|
||||
let expectedError = new Error(
|
||||
`Poll strategies are not valid. 'maxPollCount' has to be greater than 0. Invalid poll strategy: \n${JSON.stringify(
|
||||
invalidPollStrategy,
|
||||
null,
|
||||
@@ -319,27 +310,21 @@ describe('pollJobState', () => {
|
||||
)
|
||||
|
||||
await expect(
|
||||
pollJobState(
|
||||
requestClient,
|
||||
mockJob,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
pollStrategies
|
||||
)
|
||||
pollJobState(requestClient, mockJob, false, undefined, {
|
||||
...defaultPollStrategy,
|
||||
subsequentStrategies: pollStrategies
|
||||
})
|
||||
).rejects.toThrow(expectedError)
|
||||
|
||||
// INFO: 'maxPollCount' has to be > than 'maxPollCount' of the previous strategy
|
||||
const validPollStrategy = {
|
||||
maxPollCount: 5,
|
||||
pollInterval: 2,
|
||||
streamLog: false
|
||||
pollInterval: 2
|
||||
}
|
||||
|
||||
invalidPollStrategy = {
|
||||
maxPollCount: validPollStrategy.maxPollCount,
|
||||
pollInterval: 3,
|
||||
streamLog: false
|
||||
pollInterval: 3
|
||||
}
|
||||
|
||||
pollStrategies = [validPollStrategy, invalidPollStrategy]
|
||||
@@ -353,21 +338,16 @@ describe('pollJobState', () => {
|
||||
)
|
||||
|
||||
await expect(
|
||||
pollJobState(
|
||||
requestClient,
|
||||
mockJob,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
pollStrategies
|
||||
)
|
||||
pollJobState(requestClient, mockJob, false, undefined, {
|
||||
...defaultPollStrategy,
|
||||
subsequentStrategies: pollStrategies
|
||||
})
|
||||
).rejects.toThrow(expectedError)
|
||||
|
||||
// INFO: invalid 'pollInterval'
|
||||
invalidPollStrategy = {
|
||||
maxPollCount: 1,
|
||||
pollInterval: 0,
|
||||
streamLog: false
|
||||
pollInterval: 0
|
||||
}
|
||||
|
||||
pollStrategies = [invalidPollStrategy]
|
||||
@@ -381,14 +361,10 @@ describe('pollJobState', () => {
|
||||
)
|
||||
|
||||
await expect(
|
||||
pollJobState(
|
||||
requestClient,
|
||||
mockJob,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
pollStrategies
|
||||
)
|
||||
pollJobState(requestClient, mockJob, false, undefined, {
|
||||
...defaultPollStrategy,
|
||||
subsequentStrategies: pollStrategies
|
||||
})
|
||||
).rejects.toThrow(expectedError)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
export interface PollStrategy {
|
||||
maxPollCount: number
|
||||
pollInterval: number // milliseconds
|
||||
streamLog: boolean
|
||||
subsequentStrategies?: PollStrategy[]
|
||||
streamLog?: boolean
|
||||
logFolderPath?: string
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user