Skip to content
This repository has been archived by the owner on Feb 13, 2024. It is now read-only.

Commit

Permalink
Improve Retry Behaviour.
Browse files Browse the repository at this point in the history
Previously we were only retrying network errors or a 5xx error on an idempotent request (GET, HEAD, OPTIONS, PUT or DELETE).

The latter doesn't really guard/apply to us since we use POST for uploading messages. Our POST requests are effectively idempotent since we send messages with a unique message ID that is guarded by our dedupe layer (https://segment.com/blog/exactly-once-delivery/).

For us, our retry policy should be (as per https://paper.dropbox.com/doc/analytics-foo-library-guidelines-2trBhLKQD4Soz4VatvuGR#:uid=189560039280582553736180&h2=Handling-Network-Errors):

1. Retry network errors (socket timed out, etc.)
2. Retry server errors (HTTP 5xx)
3. Retry HTTP 429.
  • Loading branch information
f2prateek committed Jan 11, 2018
1 parent 5a828ee commit c48865a
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 2 deletions.
31 changes: 29 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const assert = require('assert')
const removeSlash = require('remove-trailing-slash')
const validate = require('@segment/loosely-validate-event')
const axios = require('axios')
const retries = require('axios-retry')
const axiosRetry = require('axios-retry')
const ms = require('ms')
const uid = require('crypto-token')
const version = require('./package.json').version
Expand Down Expand Up @@ -38,7 +38,10 @@ class Analytics {
this.flushInterval = options.flushInterval || 10000
this.flushed = false

retries(axios, options.retryCount || 3)
axiosRetry(axios, {
retries: options.retryCount || 3,
retryCondition: this._retryCondition
})
}

/**
Expand Down Expand Up @@ -247,6 +250,30 @@ class Analytics {
done(err)
})
}

_retryCondition (error) {
// Retry Network Errors.
if (axiosRetry.isNetworkError(error)) {
return true
}

if (!error.response) {
// Cannot determine if the request can be retried
return false
}

// Retry Server Errors (5xx).
if (error.response.status >= 500 && error.response.status <= 599) {
return true
}

// Retry if rate limited.
if (error.response.status === 429) {
return true
}

return false
}
}

module.exports = Analytics
17 changes: 17 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,23 @@ test('alias - require previousId and userId', t => {
})
})

test('retryCondition', t => {
const client = createClient()

t.false(client._retryCondition({}))

// ETIMEDOUT is retryable as per `is-retry-allowed` (used by axios-retry in `isNetworkError`).
t.true(client._retryCondition({ code: 'ETIMEDOUT' }))

// ECONNABORTED is not retryable as per `is-retry-allowed` (used by axios-retry in `isNetworkError`).
t.false(client._retryCondition({ code: 'ECONNABORTED' }))

t.true(client._retryCondition({ response: { status: 500 } }))
t.true(client._retryCondition({ response: { status: 429 } }))

t.false(client._retryCondition({ response: { status: 200 } }))
})

const { RUN_E2E_TESTS } = process.env

if (RUN_E2E_TESTS) {
Expand Down

0 comments on commit c48865a

Please sign in to comment.