node-apparatus
Version:
A mix of common components needed for awesome node experience
100 lines • 5.45 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.DistributedWindowIdentity = void 0;
const injectable_constructor_js_1 = require("../injectable-constructor/injectable-constructor.js");
const distributed_window_js_1 = require("./distributed-window.js");
/**
* A distributed window implementation that can be used to accumulate elements and drain them in a window of specific size, by their given identity.
*/
class DistributedWindowIdentity {
/**
* Creates a new instance of DistributedWindowIdentity.
* @param countWindowSize The size of the counting window. Should be more greater than 0.
* @param identityWindowSize The size of the identity window. Should be more greater than 0.
* @param distributedSortedSet The distributed sorted set to manage the identity windows.
* @param distributedAccumulatorResolver The distributed accumulator resolver to resolve the accumulator for each identity window.
* @param injectableConstructor The injectable constructor to create the distributed window instances.
* @throws Error if countWindowSize is less than or equal to 0.
* @throws Error if identityWindowSize is less than or equal to 0.
*/
constructor(countWindowSize, identityWindowSize, distributedSortedSet, distributedAccumulatorResolver, injectableConstructor = new injectable_constructor_js_1.InjectableConstructor()) {
this.countWindowSize = countWindowSize;
this.identityWindowSize = identityWindowSize;
this.distributedSortedSet = distributedSortedSet;
this.distributedAccumulatorResolver = distributedAccumulatorResolver;
this.injectableConstructor = injectableConstructor;
if (identityWindowSize <= 0)
throw new Error("identityWindowSize must be greater than 0");
if (countWindowSize <= 0)
throw new Error("countWindowSize must be greater than 0");
if (identityWindowSize === 1)
this.window = async (identity, payload) => [[payload]]; //Optimization for identityWindowSize === 1, which is just a pass-through.
}
/**
* Accumulates a new element and returns the window if the window is full.
* @param identity The identity of the payload.
* @param element The new element to be accumulated.
* @returns The window if the window size is met , otherwise undefined. It can return multiple windows if the previous windows are not drained.
* @remarks The sequence of elements can change if the drain implementation returns elements not in the multiple of countWindowSize.
*/
async window(identity, element) {
const identityBucket = identity - (identity % this.identityWindowSize);
const bucketKey = `${identityBucket}`;
const dw = await this.distributedWindowResolver(bucketKey);
const results = await dw.window(element) ?? new Array();
const inserted = await this.distributedSortedSet.add(bucketKey, identityBucket); // Instruction 1
if (inserted === true) {
const oldBuckets = await this.distributedSortedSet.drain(identityBucket, "lt"); // Instruction 2
for (const oldBucket of oldBuckets) {
const dw = await this.distributedWindowResolver(oldBucket);
const records = await dw.flush();
if (records.length > 0) {
results.push(...records);
}
}
}
return results.length === 0 ? undefined : results;
}
/**
* Tick the identity and flush the windows if the identity window is full. Use full in scenarios where the identity is time based.
* @param identity The identity to be ticked.
* @returns The windows if the identity window is full, otherwise empty array.
*/
async tickIdentity(identity) {
const identityBucket = identity - (identity % this.identityWindowSize);
const bucketKey = `${identityBucket}`;
const results = new Array();
const inserted = await this.distributedSortedSet.add(bucketKey, identityBucket); // Instruction 1
if (inserted === true) {
const oldBuckets = await this.distributedSortedSet.drain(identityBucket, "lt"); // Instruction 2
for (const oldBucket of oldBuckets) {
const dw = await this.distributedWindowResolver(oldBucket);
const records = await dw.flush();
if (records.length > 0) {
results.push(...records);
}
}
}
return results;
}
/**
* Flushes all elements from the accumulator and returns the windows.
* @returns All the pending windows.
*/
async flush() {
const allBuckets = await this.distributedSortedSet.flush();
const results = new Array();
for (const bucket of allBuckets) {
const dw = await this.distributedWindowResolver(bucket);
const records = await dw.flush();
results.push(...records);
}
return results;
}
async distributedWindowResolver(key) {
const acc = await this.distributedAccumulatorResolver(key);
return this.injectableConstructor.createInstance((distributed_window_js_1.DistributedWindow), [this.countWindowSize, acc]);
}
}
exports.DistributedWindowIdentity = DistributedWindowIdentity;
//# sourceMappingURL=distributed-window-identity.js.map