feat(persist-through-conflicts): use exponential backoff

This commit is contained in:
Geoff Cox 2017-09-13 16:07:14 -07:00
parent 87587338cf
commit 25b4bc1fdb
2 changed files with 26 additions and 18 deletions

View file

@ -2,7 +2,8 @@
var promisedRequest = require('./request'),
CouchPersistentStreamIterator = require('./couch-persistent-stream-iterator'),
sporks = require('sporks');
sporks = require('sporks'),
Backoff = require('backoff-promise');
var Doc = function (slouch) {
this._slouch = slouch;
@ -159,27 +160,33 @@ Doc.prototype.createOrUpdateIgnoreConflict = function (dbName, doc) {
});
};
// Provide a construct for mocking
Doc.prototype._newBackoff = function () {
return new Backoff();
};
Doc.prototype._persistThroughConflicts = function (promiseFactory) {
var self = this,
i = 0;
// Use an exponential backoff to prevent multiple ticks from competing with each other and
// resulting in none of the ticks persisting through the conflict within the allotted number of
// retries.
var backoff = self._newBackoff();
var run = function () {
return promiseFactory().catch(function (err) {
if (err.error === 'conflict' && i++ < self.maxRetries) { // conflict?
// Retry
return backoff.attempt(function () {
return promiseFactory();
}).catch(function (err) {
// Conflict and haven't reached max retries?
if (err.error === 'conflict' && i++ < self.maxRetries) {
// Attempt again
return run();
} else {
// Unexpected error
throw err;
}
});
};

View file

@ -4,7 +4,8 @@ var Slouch = require('../../scripts'),
utils = require('../utils'),
sporks = require('sporks'),
Promise = require('sporks/scripts/promise'),
config = require('../config.json');
config = require('../config.json'),
Backoff = require('backoff-promise');
describe('doc', function () {
@ -19,6 +20,12 @@ describe('doc', function () {
slouch = new Slouch(utils.couchDBURL());
db = slouch.db;
updates = [];
// Shorten backoff
slouch.doc._newBackoff = function () {
return new Backoff(1);
};
return utils.createDB();
});
@ -265,8 +272,6 @@ describe('doc', function () {
});
it('upsert should fail after max retries', function () {
slouch.maxRetries = 3;
// Disable for conflict faking
slouch.doc.ignoreDuplicateUpdates = false;
@ -347,8 +352,6 @@ describe('doc', function () {
});
it('get, merge and upsert should fail after max retries', function () {
slouch.maxRetries = 3;
// Disable for conflict faking
slouch.doc.ignoreDuplicateUpdates = false;
@ -382,8 +385,6 @@ describe('doc', function () {
});
it('get, modify and upsert should fail after max retries', function () {
slouch.maxRetries = 3;
return fakeConflict().then(function () {
return sporks.shouldThrow(function () {
return slouch.doc.getModifyUpsert(utils.createdDB, '1', function (doc) {