firelease
Version:
Firebase queue consumer for Node with at-least-once semantics
129 lines • 5.8 kB
JavaScript
"use strict";
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
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 __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var _FireleaseStats_getStuckTasks;
Object.defineProperty(exports, "__esModule", { value: true });
exports.FireleaseStats = exports.QueueStats = exports.QueueSourceStats = void 0;
const lodash_1 = __importDefault(require("lodash"));
function createLeaseTransactionStats() {
return { acquired: 0, contended: 0, failed: 0, tries: 0, duration: 0 };
}
function rollUpLeaseTransactions(items) {
const result = createLeaseTransactionStats();
result.acquired = lodash_1.default.sumBy(items, 'acquired');
result.contended = lodash_1.default.sumBy(items, 'contended');
result.failed = lodash_1.default.sumBy(items, 'failed');
result.tries = lodash_1.default.sumBy(items, 'tries');
const attemptedItems = lodash_1.default.filter(items, countLeaseAttempts);
if (attemptedItems.length)
result.duration = lodash_1.default.meanBy(attemptedItems, 'duration');
return result;
}
function countLeaseAttempts(stats) {
return stats.acquired + stats.contended + stats.failed;
}
function exposeGetters(instance, properties) {
const prototype = Object.getPrototypeOf(instance);
for (const property of properties) {
const descriptor = Object.getOwnPropertyDescriptor(prototype, property);
Object.defineProperty(instance, property, { ...descriptor, enumerable: true });
}
}
class QueueSourceStats {
constructor(ref) {
this.ref = ref;
this.connected = false;
this.mode = 'safe';
this.size = null;
this.healthy = true;
this.latency = null;
this.leaseTransactions = createLeaseTransactionStats();
}
}
exports.QueueSourceStats = QueueSourceStats;
class QueueStats {
constructor(ref, key, sources) {
this.ref = ref;
this.key = key;
this.sources = sources;
this.tasksAcquired = 0;
exposeGetters(this, ['mode', 'size', 'sizeDelta', 'sizeTimestamp', 'healthy', 'maxLatency', 'leaseTransactions']);
}
get mode() {
const modes = lodash_1.default.uniq(lodash_1.default.map(this.sources, 'mode'));
return modes.length === 1 ? modes[0] : 'mixed';
}
get size() {
const sizes = lodash_1.default.map(this.sources, 'size');
return lodash_1.default.every(sizes, lodash_1.default.isNumber) ? lodash_1.default.sum(sizes) : null;
}
get sizeDelta() {
const deltas = lodash_1.default.map(this.sources, 'sizeDelta');
return lodash_1.default.every(deltas, lodash_1.default.isNumber) ? lodash_1.default.sum(deltas) : undefined;
}
get sizeTimestamp() {
return (0, lodash_1.default)(this.sources).map('sizeTimestamp').filter(lodash_1.default.isNumber).min();
}
get healthy() {
return lodash_1.default.every(this.sources, source => source.connected && source.healthy);
}
get maxLatency() {
return (0, lodash_1.default)(this.sources).map('latency').max() || 0;
}
get leaseTransactions() {
return rollUpLeaseTransactions(lodash_1.default.map(this.sources, 'leaseTransactions'));
}
}
exports.QueueStats = QueueStats;
class FireleaseStats {
constructor(getStuckTasks) {
_FireleaseStats_getStuckTasks.set(this, void 0);
this.queues = [];
__classPrivateFieldSet(this, _FireleaseStats_getStuckTasks, getStuckTasks, "f");
exposeGetters(this, [
'healthy', 'sickQueues', 'sickSources', 'stuckTasks', 'maxLatency', 'leaseTransactions',
'tasksAcquired'
]);
}
get healthy() {
return lodash_1.default.every(this.queues, 'healthy');
}
get sickQueues() {
return (0, lodash_1.default)(this.queues).reject('healthy').map('key').value();
}
get sickSources() {
return (0, lodash_1.default)(this.queues)
.flatMap(queue => queue.sources)
.reject(source => source.connected && source.healthy)
.map(source => source.ref)
.uniq()
.value();
}
get stuckTasks() {
return __classPrivateFieldGet(this, _FireleaseStats_getStuckTasks, "f").call(this);
}
get maxLatency() {
return (0, lodash_1.default)(this.queues).map('maxLatency').max() || 0;
}
get leaseTransactions() {
return rollUpLeaseTransactions(lodash_1.default.map(this.queues, 'leaseTransactions'));
}
get tasksAcquired() {
return lodash_1.default.sumBy(this.queues, queue => queue.tasksAcquired);
}
}
exports.FireleaseStats = FireleaseStats;
_FireleaseStats_getStuckTasks = new WeakMap();
//# sourceMappingURL=stats.js.map