Skip to content

Commit

Permalink
feat: add retry method
Browse files Browse the repository at this point in the history
  • Loading branch information
thetutlage committed May 19, 2022
1 parent db3da0e commit 024348c
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 0 deletions.
45 changes: 45 additions & 0 deletions src/Request/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,51 @@ export class ApiRequest extends Macroable {
return this
}

/**
* Retry a failing request. Along with the count, you can also define
* a callback to decide how long the request should be retried.
*
* The max count is applied regardless of whether callback is defined
* or not
*
* The following response codes are considered failing.
* - 408
* - 413
* - 429
* - 500
* - 502
* - 503
* - 504
* - 521
* - 522
* - 524
*
* The following error codes are considered failing.
* - 'ETIMEDOUT'
* - 'ECONNRESET'
* - 'EADDRINUSE'
* - 'ECONNREFUSED'
* - 'EPIPE'
* - 'ENOTFOUND'
* - 'ENETUNREACH'
* - 'EAI_AGAIN'
*/
public retry(
count: number,
retryUntilCallback?: (error: any, response: ApiResponse) => boolean
): this {
if (retryUntilCallback) {
this.request.retry(count, (error, response) => {
return retryUntilCallback(error, new ApiResponse(this, response, this.config, this.assert))
})

return this
}

this.request.retry(count)
return this
}

/**
* Make the API request
*/
Expand Down
69 changes: 69 additions & 0 deletions tests/request/base.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { RequestConfig } from '../../src/Contracts'

import { httpServer } from '../../test-helpers'
import { IncomingMessage } from 'http'
import { ApiResponse } from '../../src/Response'

test.group('Request', (group) => {
group.each.setup(async () => {
Expand Down Expand Up @@ -77,4 +78,72 @@ test.group('Request', (group) => {
*/
serverRequest!.socket.destroy()
})

test('retry failing requests for the given number of count', async ({ assert }) => {
let retries = 0

httpServer.onRequest(async (_, res) => {
retries++
res.statusCode = 408
res.end()
})

const request = new ApiRequest({ baseUrl: httpServer.baseUrl, method: 'GET', endpoint: '/' })
await request.accept('json').retry(3)

assert.equal(retries, 4)
})

test('retry failing request until the callback returns false', async ({ assert }) => {
let retries = 0

httpServer.onRequest(async (_, res) => {
retries++
res.statusCode = 408
res.end()
})

const request = new ApiRequest({ baseUrl: httpServer.baseUrl, method: 'GET', endpoint: '/' })
await request.accept('json').retry(Infinity, () => {
return retries < 6
})

assert.equal(retries, 6)
})

test('respect max count even when callback returns true', async ({ assert }) => {
let retries = 0

httpServer.onRequest(async (_, res) => {
retries++
res.statusCode = 408
res.end()
})

const request = new ApiRequest({ baseUrl: httpServer.baseUrl, method: 'GET', endpoint: '/' })
await request.accept('json').retry(3, () => {
return retries < 6
})

assert.equal(retries, 4)
})

test('access response within the retry callback', async ({ assert }) => {
let retries = 0

httpServer.onRequest(async (_, res) => {
retries++
res.statusCode = 408
res.end()
})

const request = new ApiRequest({ baseUrl: httpServer.baseUrl, method: 'GET', endpoint: '/' })
await request.accept('json').retry(3, (error, response) => {
assert.isNull(error)
assert.instanceOf(response, ApiResponse)
return retries < 6
})

assert.equal(retries, 4)
})
})

0 comments on commit 024348c

Please sign in to comment.