From df2d376c18dfd22f7bfb0285de49e419c395c783 Mon Sep 17 00:00:00 2001 From: Don Date: Sun, 11 Dec 2022 21:18:43 -0700 Subject: [PATCH 1/3] add support to request rev via HEAD --- scripts/doc.js | 10 +++++ scripts/enhanced-request.js | 84 +++++++++++++++++++------------------ 2 files changed, 54 insertions(+), 40 deletions(-) diff --git a/scripts/doc.js b/scripts/doc.js index 86f00d2..6bf151b 100644 --- a/scripts/doc.js +++ b/scripts/doc.js @@ -95,6 +95,16 @@ Doc.prototype.get = function (dbName, docId, params) { }); }; +Doc.prototype.rev = function (dbName, docId, params) { + return this._slouch._req({ + uri: this._slouch._url + '/' + encodeURIComponent(dbName) + '/' + encodeURIComponent( + docId), + method: 'HEAD', + qs: params, + parseBody: false + }).then(function (headers) { return headers.etag; }); +}; + Doc.prototype.getIgnoreMissing = function (dbName, id) { var self = this; return self.ignoreMissing(function () { diff --git a/scripts/enhanced-request.js b/scripts/enhanced-request.js index 1f5f7e3..393c515 100644 --- a/scripts/enhanced-request.js +++ b/scripts/enhanced-request.js @@ -49,10 +49,10 @@ EnhancedRequest.MAX_RETRIES = 10; // Preserve some compatibility with nano EnhancedRequest.prototype._getStatusCode = function (body) { switch (body.error) { - case 'conflict': - return 409; - case 'not_found': - return 404; + case 'conflict': + return 409; + case 'not_found': + return 404; } if (body.reason && body.reason.indexOf('Could not open source database') !== -1) { @@ -125,6 +125,10 @@ EnhancedRequest.prototype._request = function (opts) { // Sometimes CouchDB just returns an malformed error if (!response || !response.body) { + if (response && opts.method === 'HEAD') { + // or we only want the response headers + return response.headers; + } err = new Error('malformed body'); err.error = 'malformed body'; self._log('Slouch Request:', { @@ -181,42 +185,42 @@ EnhancedRequest.prototype._throttledEnhancedRequest = function () { EnhancedRequest.prototype._shouldReconnect = function (err) { switch (err.message) { - case 'all_dbs_active': // No more connections - return true; - - default: - return new RegExp([ - // Connection refused, e.g. because the CouchDB server is being restarted. - 'ECONNREFUSED', - - 'ENETUNREACH', // can occur when box sleeps/wakes-up - - // Occurs randomly when many simultaenous connections: - 'emfile', - 'socket hang up', - 'ECONNRESET', - 'ETIMEDOUT', - 'function_clause', - 'unknown_error', - 'internal_server_error', - - 'Failed to fetch', // ECONNREFUSED/ENOTFOUND in Chrome - 'Type error', // ECONNREFUSED/ENOTFOUND in Safari - 'XHR error', // ECONNREFUSED/ENOTFOUND in Firefox - 'EAI_AGAIN' // Transient DNS error - - // TODO: It is not clear why CouchDB responds with these timeout errors and immediately - // retrying the request often leads to deadlocks when you are continuously listening. In - // practice, it is better that your app throws a fatal error and then is restarted, e.g. via - // Docker, as this seems to reliably recover from this state. At some point we should analyze - // this better and determine where the bug lies and fix it at the root cause: - // https://github.com/redgeoff/spiegel/issues/100 - // - // Occurs randomly even when there is a relatively small amount of data, e.g. "The request - // could not be processed in a reasonable amount of time" - // - // 'timeout' - ].join('|'), 'i').test(err.message); + case 'all_dbs_active': // No more connections + return true; + + default: + return new RegExp([ + // Connection refused, e.g. because the CouchDB server is being restarted. + 'ECONNREFUSED', + + 'ENETUNREACH', // can occur when box sleeps/wakes-up + + // Occurs randomly when many simultaenous connections: + 'emfile', + 'socket hang up', + 'ECONNRESET', + 'ETIMEDOUT', + 'function_clause', + 'unknown_error', + 'internal_server_error', + + 'Failed to fetch', // ECONNREFUSED/ENOTFOUND in Chrome + 'Type error', // ECONNREFUSED/ENOTFOUND in Safari + 'XHR error', // ECONNREFUSED/ENOTFOUND in Firefox + 'EAI_AGAIN' // Transient DNS error + + // TODO: It is not clear why CouchDB responds with these timeout errors and immediately + // retrying the request often leads to deadlocks when you are continuously listening. In + // practice, it is better that your app throws a fatal error and then is restarted, e.g. via + // Docker, as this seems to reliably recover from this state. At some point we should analyze + // this better and determine where the bug lies and fix it at the root cause: + // https://github.com/redgeoff/spiegel/issues/100 + // + // Occurs randomly even when there is a relatively small amount of data, e.g. "The request + // could not be processed in a reasonable amount of time" + // + // 'timeout' + ].join('|'), 'i').test(err.message); } }; From 840e866e80b24ff64e7d30321c43bce870b7bd38 Mon Sep 17 00:00:00 2001 From: Don Date: Mon, 12 Dec 2022 13:26:48 -0700 Subject: [PATCH 2/3] handle entire response being returned --- scripts/doc.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/doc.js b/scripts/doc.js index 6bf151b..be94250 100644 --- a/scripts/doc.js +++ b/scripts/doc.js @@ -102,7 +102,7 @@ Doc.prototype.rev = function (dbName, docId, params) { method: 'HEAD', qs: params, parseBody: false - }).then(function (headers) { return headers.etag; }); + }).then(function (response) { return response.headers.etag; }); }; Doc.prototype.getIgnoreMissing = function (dbName, id) { From 7ed5ce61de60cdaefd5e34d090917c18b2412fed Mon Sep 17 00:00:00 2001 From: Don Date: Mon, 12 Dec 2022 13:34:24 -0700 Subject: [PATCH 3/3] return full response for HEAD --- scripts/enhanced-request.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/enhanced-request.js b/scripts/enhanced-request.js index 393c515..7487daa 100644 --- a/scripts/enhanced-request.js +++ b/scripts/enhanced-request.js @@ -126,8 +126,8 @@ EnhancedRequest.prototype._request = function (opts) { // Sometimes CouchDB just returns an malformed error if (!response || !response.body) { if (response && opts.method === 'HEAD') { - // or we only want the response headers - return response.headers; + // or we only want the response/headers + return response; } err = new Error('malformed body'); err.error = 'malformed body';