@bcc-code/feathers-arangodb
Version:
ArangoDB Service/Adapter for FeathersJS
110 lines (109 loc) • 4.23 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RetryConnection = exports.RetryDatabase = void 0;
const aql_1 = require("arangojs/aql");
const connection_1 = require("arangojs/connection");
const error_1 = require("arangojs/error");
const auto_database_1 = require("./auto-database");
class RetryDatabase extends auto_database_1.AutoDatabse {
constructor(config) {
var _a;
super(config);
this.retryOnConflict = (_a = config === null || config === void 0 ? void 0 : config.retryOnConflict) !== null && _a !== void 0 ? _a : 0;
this._connection = new RetryConnection(config);
}
query(query, bindVars, options = {}) {
var _a;
if ((0, aql_1.isAqlQuery)(query)) {
options = bindVars !== null && bindVars !== void 0 ? bindVars : {};
bindVars = query.bindVars;
query = query.query;
}
else if ((0, aql_1.isAqlLiteral)(query)) {
query = query.toAQL();
}
options.retryOnConflict = (_a = options.retryOnConflict) !== null && _a !== void 0 ? _a : this.retryOnConflict;
return super.query(query, bindVars, options);
}
}
exports.RetryDatabase = RetryDatabase;
class RetryConnection extends connection_1.Connection {
_runQueue() {
if (!this._queue.length || this._activeTasks >= this._maxTasks)
return;
const task = this._queue.shift();
if (!task)
return;
let host = this._activeHost;
if (task.host !== undefined) {
host = task.host;
}
else if (task.allowDirtyRead) {
host = this._activeDirtyHost;
this._activeDirtyHost = (this._activeDirtyHost + 1) % this._hosts.length;
task.options.headers["x-arango-allow-dirty-read"] = "true";
}
else if (this._loadBalancingStrategy === "ROUND_ROBIN") {
this._activeHost = (this._activeHost + 1) % this._hosts.length;
}
this._activeTasks += 1;
const callback = (err, res) => {
this._activeTasks -= 1;
if (err) {
if (!task.allowDirtyRead &&
this._hosts.length > 1 &&
this._activeHost === host &&
this._useFailOver) {
this._activeHost = (this._activeHost + 1) % this._hosts.length;
}
else if (!task.host &&
this._shouldRetry &&
task.retries < (this._maxRetries || this._hosts.length - 1) &&
(0, error_1.isSystemError)(err) &&
err.syscall === "connect" &&
err.code === "ECONNREFUSED") {
task.retries += 1;
this._queue.push(task);
}
else {
if (task.stack) {
err.stack += task.stack();
}
task.reject(err);
}
}
else {
const response = res;
if (!response)
return;
if (response.statusCode === 409 && task.retryOnConflict > 0) {
task.retryOnConflict -= 1;
this._queue.push(task);
}
else if (response.statusCode === 503 &&
response.headers["x-arango-endpoint"]) {
const url = response.headers["x-arango-endpoint"];
const [index] = this.addToHostList(url);
task.host = index;
if (this._activeHost === host) {
this._activeHost = index;
}
this._queue.push(task);
}
else {
response.arangojsHostId = host;
task.resolve(response);
}
}
this._runQueue();
};
try {
this._hosts[host](task.options, callback);
}
catch (e) {
if (e instanceof Error)
callback(e);
}
}
}
exports.RetryConnection = RetryConnection;