firewalk
Version:
A collection traversal library for Firestore
107 lines • 7.11 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _PromiseQueueBasedTraverserImpl_instances, _a, _PromiseQueueBasedTraverserImpl_defaultConfig, _PromiseQueueBasedTraverserImpl_makeRetriableAccordingToConfig, _PromiseQueueBasedTraverserImpl_getProcessableItemCount, _PromiseQueueBasedTraverserImpl_getProcessQueueInterval;
Object.defineProperty(exports, "__esModule", { value: true });
exports.PromiseQueueBasedTraverserImpl = void 0;
const errors_1 = require("../../errors");
const errors_2 = require("../errors");
const ds_1 = require("../ds");
const utils_1 = require("../utils");
const abstract_1 = require("./abstract");
class PromiseQueueBasedTraverserImpl extends abstract_1.AbstractTraverser {
constructor(traversable, exitEarlyPredicates = [], config) {
super(Object.assign(Object.assign({}, __classPrivateFieldGet(_a, _a, "f", _PromiseQueueBasedTraverserImpl_defaultConfig)), config), exitEarlyPredicates);
_PromiseQueueBasedTraverserImpl_instances.add(this);
this.traversable = traversable;
}
withConfig(config) {
return new _a(this.traversable, this.exitEarlyPredicates, Object.assign(Object.assign({}, this.traversalConfig), config));
}
withExitEarlyPredicate(predicate) {
return new _a(this.traversable, [...this.exitEarlyPredicates, predicate], this.traversalConfig);
}
traverse(callback) {
return __awaiter(this, void 0, void 0, function* () {
const { traversalConfig } = this;
const { maxConcurrentBatchCount } = traversalConfig;
callback = __classPrivateFieldGet(this, _PromiseQueueBasedTraverserImpl_instances, "m", _PromiseQueueBasedTraverserImpl_makeRetriableAccordingToConfig).call(this, callback);
if (maxConcurrentBatchCount === 1) {
return this.runTraversal((batchDocs, batchIndex) => __awaiter(this, void 0, void 0, function* () {
yield callback(batchDocs, batchIndex);
}));
}
const callbackPromiseQueue = new ds_1.PromiseQueue();
const unregisterQueueProcessor = (0, utils_1.registerInterval)(() => __awaiter(this, void 0, void 0, function* () {
if (!callbackPromiseQueue.isProcessing) {
const processableItemCount = __classPrivateFieldGet(this, _PromiseQueueBasedTraverserImpl_instances, "m", _PromiseQueueBasedTraverserImpl_getProcessableItemCount).call(this, callbackPromiseQueue.size);
try {
yield callbackPromiseQueue.processFirst(processableItemCount);
}
catch (err) {
throw err instanceof errors_2.IllegalArgumentError
? new errors_1.ImplementationError(`Encountered an expected error originating from an incorrectly implemented PromiseQueue data structure.`)
: err;
}
}
}), () => __classPrivateFieldGet(this, _PromiseQueueBasedTraverserImpl_instances, "m", _PromiseQueueBasedTraverserImpl_getProcessQueueInterval).call(this, callbackPromiseQueue.size));
const traversalResult = yield this.runTraversal((batchDocs, batchIndex) => {
var _b;
callbackPromiseQueue.enqueue((_b = callback(batchDocs, batchIndex)) !== null && _b !== void 0 ? _b : Promise.resolve());
return () => __awaiter(this, void 0, void 0, function* () {
while (callbackPromiseQueue.size >= maxConcurrentBatchCount) {
// TODO: There probably is a better way to compute sleep duration
const processQueueInterval = __classPrivateFieldGet(this, _PromiseQueueBasedTraverserImpl_instances, "m", _PromiseQueueBasedTraverserImpl_getProcessQueueInterval).call(this, callbackPromiseQueue.size);
yield (0, utils_1.sleep)(processQueueInterval);
}
});
});
yield unregisterQueueProcessor();
// There may still be some Promises left in the queue but there won't be any new ones coming in.
// Wait for the existing ones to resolve and exit.
yield callbackPromiseQueue.processAll();
return traversalResult;
});
}
}
exports.PromiseQueueBasedTraverserImpl = PromiseQueueBasedTraverserImpl;
_a = PromiseQueueBasedTraverserImpl, _PromiseQueueBasedTraverserImpl_instances = new WeakSet(), _PromiseQueueBasedTraverserImpl_makeRetriableAccordingToConfig = function _PromiseQueueBasedTraverserImpl_makeRetriableAccordingToConfig(callback) {
const { maxBatchRetryCount, sleepTimeBetweenTrials } = this.traversalConfig;
let cb = callback;
if (maxBatchRetryCount > 0) {
const retriableCallback = (0, utils_1.makeRetriable)(callback, {
maxTrialCount: 1 + maxBatchRetryCount,
sleepTimeBetweenTrials,
returnErrors: true,
});
cb = (...args) => __awaiter(this, void 0, void 0, function* () {
const result = yield retriableCallback(...args);
if (!result.hasSucceeded) {
const { errors } = result;
const lastError = errors[errors.length - 1];
throw lastError;
}
});
}
return cb;
}, _PromiseQueueBasedTraverserImpl_getProcessableItemCount = function _PromiseQueueBasedTraverserImpl_getProcessableItemCount(queueSize) {
// TODO: Implement using traversal config and queue size
return queueSize;
}, _PromiseQueueBasedTraverserImpl_getProcessQueueInterval = function _PromiseQueueBasedTraverserImpl_getProcessQueueInterval(queueSize) {
// TODO: Implement using traversal config and queue size
return 250;
};
_PromiseQueueBasedTraverserImpl_defaultConfig = { value: Object.assign({}, abstract_1.AbstractTraverser.baseConfig) };
//# sourceMappingURL=PromiseQueueBasedTraverserImpl.js.map