1
0
mirror of https://github.com/sasjs/adapter.git synced 2026-01-06 20:10:05 +00:00

Merge pull request #491 from sasjs/session-state-fix

fix(session): remove retry limit if could not get state
This commit is contained in:
Yury Shkoda
2021-07-29 10:34:50 +03:00
committed by GitHub
2 changed files with 141 additions and 78 deletions

View File

@@ -5,10 +5,10 @@ import { prefixMessage } from '@sasjs/utils/error'
import { RequestClient } from './request/RequestClient'
const MAX_SESSION_COUNT = 1
const RETRY_LIMIT: number = 3
let RETRY_COUNT: number = 0
export class SessionManager {
private loggedErrors: NoSessionStateError[] = []
constructor(
private serverUrl: string,
private contextName: string,
@@ -154,14 +154,13 @@ export class SessionManager {
session: Session,
etag: string | null,
accessToken?: string
) {
): Promise<string> {
const logger = process.logger || console
let sessionState = session.state
const stateLink = session.links.find((l: any) => l.rel === 'state')
return new Promise(async (resolve, reject) => {
if (
sessionState === 'pending' ||
sessionState === 'running' ||
@@ -192,31 +191,38 @@ export class SessionManager {
this.printedSessionState.printed = false
}
// There is an internal error present in SAS Viya 3.5
// Retry to wait for a session status in such case of SAS internal error
if (!sessionState) {
if (RETRY_COUNT < RETRY_LIMIT) {
RETRY_COUNT++
resolve(this.waitForSession(session, etag, accessToken))
} else {
reject(
new NoSessionStateError(
const stateError = new NoSessionStateError(
responseStatus,
this.serverUrl + stateLink.href,
session.links.find((l: any) => l.rel === 'log')
?.href as string
session.links.find((l: any) => l.rel === 'log')?.href as string
)
if (
!this.loggedErrors.find(
(err: NoSessionStateError) =>
err.serverResponseStatus === stateError.serverResponseStatus
)
}
) {
this.loggedErrors.push(stateError)
logger.info(stateError.message)
}
resolve(sessionState)
return await this.waitForSession(session, etag, accessToken)
}
this.loggedErrors = []
return sessionState
} else {
throw 'Error while getting session state link.'
}
} else {
resolve(sessionState)
this.loggedErrors = []
return sessionState
}
})
}
private async getSessionState(

View File

@@ -3,6 +3,8 @@ import { RequestClient } from '../request/RequestClient'
import { NoSessionStateError } from '../types/errors'
import * as dotenv from 'dotenv'
import axios from 'axios'
import { Logger, LogLevel } from '@sasjs/utils'
import { Session } from '../types'
jest.mock('axios')
const mockedAxios = axios as jest.Mocked<typeof axios>
@@ -47,36 +49,91 @@ describe('SessionManager', () => {
})
describe('waitForSession', () => {
it('should reject with NoSessionStateError if SAS server did not provide session state', async () => {
const responseStatus = 304
mockedAxios.get.mockImplementation(() =>
Promise.resolve({ data: '', status: responseStatus })
)
await expect(
sessionManager['waitForSession'](
{
const session: Session = {
id: 'id',
state: '',
links: [
{ rel: 'state', href: '', uri: '', type: '', method: 'GET' }
],
links: [{ rel: 'state', href: '', uri: '', type: '', method: 'GET' }],
attributes: {
sessionInactiveTimeout: 0
},
creationTimeStamp: ''
},
null,
'access_token'
}
beforeEach(() => {
;(process as any).logger = new Logger(LogLevel.Off)
})
it('should reject with NoSessionStateError if SAS server did not provide session state', async () => {
let requestAttempt = 0
const requestAttemptLimit = 10
const sessionState = 'idle'
mockedAxios.get.mockImplementation(() => {
requestAttempt += 1
if (requestAttempt >= requestAttemptLimit) {
return Promise.resolve({ data: sessionState, status: 200 })
}
return Promise.resolve({ data: '', status: 304 })
})
jest.spyOn((process as any).logger, 'info')
sessionManager.debug = true
await expect(
sessionManager['waitForSession'](session, null, 'access_token')
).resolves.toEqual(sessionState)
expect(mockedAxios.get).toHaveBeenCalledTimes(requestAttemptLimit)
expect((process as any).logger.info).toHaveBeenCalledTimes(3)
expect((process as any).logger.info).toHaveBeenNthCalledWith(
1,
'Polling session status...'
)
).rejects.toEqual(
new NoSessionStateError(
responseStatus,
process.env.SERVER_URL as string,
'logUrl'
expect((process as any).logger.info).toHaveBeenNthCalledWith(
2,
`Could not get session state. Server responded with 304 whilst checking state: ${process.env.SERVER_URL}`
)
expect((process as any).logger.info).toHaveBeenNthCalledWith(
3,
`Current session state is '${sessionState}'`
)
})
it('should throw an error if there is no session link', async () => {
const customSession = JSON.parse(JSON.stringify(session))
customSession.links = []
mockedAxios.get.mockImplementation(() =>
Promise.resolve({ data: customSession.state, status: 200 })
)
await expect(
sessionManager['waitForSession'](customSession, null, 'access_token')
).rejects.toContain('Error while getting session state link.')
})
it('should throw an error if could not get session state', async () => {
mockedAxios.get.mockImplementation(() => Promise.reject('Mocked error'))
await expect(
sessionManager['waitForSession'](session, null, 'access_token')
).rejects.toContain('Error while getting session state.')
})
it('should return session state', async () => {
const customSession = JSON.parse(JSON.stringify(session))
customSession.state = 'completed'
mockedAxios.get.mockImplementation(() =>
Promise.resolve({ data: customSession.state, status: 200 })
)
await expect(
sessionManager['waitForSession'](customSession, null, 'access_token')
).resolves.toEqual(customSession.state)
})
})
})