Skip to content

Commit

Permalink
feat(http-middleware): add retryOnAbort config
Browse files Browse the repository at this point in the history
- add config to enable retry an aborted request
  • Loading branch information
ajimae committed Oct 14, 2021
1 parent 9034675 commit 6edfdb8
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 9 deletions.
35 changes: 26 additions & 9 deletions packages/sdk-middleware-http/src/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export default function createHttpMiddleware({
backoff = true,
retryDelay = 200,
maxDelay = Infinity,
retryOnAbort = false,
} = {},
fetch: fetcher,
abortController: _abortController,
Expand Down Expand Up @@ -98,13 +99,6 @@ export default function createHttpMiddleware({
response: MiddlewareResponse
) => {
let abortController: any
if (timeout || getAbortController || _abortController)
// eslint-disable-next-line
abortController =
(getAbortController ? getAbortController() : null) ||
_abortController ||
new AbortController()

const url = host.replace(/\/$/, '') + request.uri
const body =
typeof request.body === 'string' || Buffer.isBuffer(request.body)
Expand All @@ -126,15 +120,38 @@ export default function createHttpMiddleware({
if (credentialsMode) {
fetchOptions.credentials = credentialsMode
}
if (abortController) {
fetchOptions.signal = abortController.signal

if (!retryOnAbort) {
if (timeout || getAbortController || _abortController)
// eslint-disable-next-line
abortController =
(getAbortController ? getAbortController() : null) ||
_abortController ||
new AbortController()

if (abortController) {
fetchOptions.signal = abortController.signal
}
}

if (body) {
fetchOptions.body = body
}
let retryCount = 0
// wrap in a fn so we can retry if error occur
function executeFetch() {
if (retryOnAbort) {
if (timeout || getAbortController || _abortController)
// eslint-disable-next-line
abortController =
(getAbortController ? getAbortController() : null) ||
_abortController ||
new AbortController()

if (abortController) {
fetchOptions.signal = abortController.signal
}
}
// Kick off timer for abortController directly before fetch.
let timer
if (timeout)
Expand Down
85 changes: 85 additions & 0 deletions packages/sdk-middleware-http/test/http.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1116,4 +1116,89 @@ describe('Http', () => {

httpMiddleware(next)(request, response)
}))

test('should retry when request is aborted (success)', () => {
expect.assertions(1)
return new Promise((resolve, reject) => {
const request = createTestRequest({
uri: '/foo/bar',
})
const response = { resolve, reject }
const next = (req, res) => {
expect(res).toEqual({
...response,
body: { foo: 'bar' },
statusCode: 200,
})
resolve()
}
// Use default options
const httpMiddleware = createHttpMiddleware({
host: testHost,
timeout: 100,
fetch,
enableRetry: true,
retryConfig: {
retryOnAbort: true,
},
getAbortController: () => new AbortController(),
})
nock(testHost)
.defaultReplyHeaders({
'Content-Type': 'application/json',
})
.get('/foo/bar')
.once()
.delay(200) // delay response to fail
.reply(200, { foo: 'bar' })
.get('/foo/bar')
.delay(50) // delay lower then timeout
.reply(200, { foo: 'bar' })

httpMiddleware(next)(request, response)
})
})

test('should retry when requests are aborted (fail)', () => {
expect.assertions(1)
return new Promise((resolve, reject) => {
const request = createTestRequest({
uri: '/foo/bar',
})
const response = { resolve, reject }
const next = (req, res) => {
expect(res).toEqual({
...response,
error: expect.any(Error),
statusCode: 0,
})
resolve()
}
// Use default options
const httpMiddleware = createHttpMiddleware({
host: testHost,
timeout: 100, // time out after 10ms
fetch,
enableRetry: true,
retryConfig: {
maxRetries: 1,
retryOnAbort: true,
},
getAbortController: () => new AbortController(),
})
nock(testHost)
.defaultReplyHeaders({
'Content-Type': 'application/json',
})
.get('/foo/bar')
.once()
.delay(150) // delay response to fail (higher than timeout)
.reply(200, { foo: 'bar' })
.get('/foo/bar')
.delay(150) // delay response to fail (higher than timeout)
.reply(200, { foo: 'bar' })

httpMiddleware(next)(request, response)
})
})
})
1 change: 1 addition & 0 deletions types/sdk.js
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ export type HttpMiddlewareOptions = {
retryDelay?: number,
backoff?: boolean,
maxDelay?: number,
retryOnAbort: boolean
},
fetch?: typeof fetch,
/**
Expand Down

0 comments on commit 6edfdb8

Please sign in to comment.