multiconsumer-queue
Version:
A wrapper to build multiconsumer queues
167 lines • 5.24 kB
JavaScript
"use strict";
/*
* Copyright (c) 2017 by The MultiConsumer Queue Project Developers.
* Some rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
Object.defineProperty(exports, "__esModule", { value: true });
const immutable_1 = require("immutable");
/**
* QueueTopic constructor
* @constructor
*/
function QueueTopic(topic) {
return topic;
}
exports.QueueTopic = QueueTopic;
/**
* ConsumerGroupId constructor
* @constructor
*/
function ConsumerGroupId(groupId) {
return groupId;
}
exports.ConsumerGroupId = ConsumerGroupId;
/**
* Wraps a {@Link NamedQueue} with given name, exposing {@Link Queue} interface
*/
class NamedQueueWrap {
constructor(_topic, _out) {
this._topic = _topic;
this._out = _out;
}
add(data) {
this._out.add(this._topic, data);
}
process(fn, n) {
this._out.process(this._topic, fn, n);
}
}
exports.NamedQueueWrap = NamedQueueWrap;
/**
* Passes calls to out {@Link NamedQueue} but transforming input topic name using given map function
*/
class DynamicallyNamedQueue {
constructor(topic, out) {
this.topic = topic;
this.out = out;
}
add(topic, data) {
this.out.add(this.topic(topic), data);
}
process(topic, fn, n) {
this.out.process(this.topic(topic), fn, n);
}
}
exports.DynamicallyNamedQueue = DynamicallyNamedQueue;
/**
* {@Link MultiConsumerQueue} implementation helper
*
* Dispatches messages from source Queue to out {@Link NamedQueue} using all group IDs
* (syncronized using a RedisLiveSet) as topic names
*/
class MultiConsumerQueueImpl {
/**
* @param _source queue to add and dispatch messages from
* @param _out a named queue to attach final processors to using groupId as topic name
* @param _groups live set to synchronize consumer groups across nodes
* @param _jobDataLens lens to extract data from Job, to support multiple implementations
*/
constructor(_source, _out, _groups, _jobDataLens, _lastGroupsSet = immutable_1.Set()) {
this._source = _source;
this._out = _out;
this._groups = _groups;
this._jobDataLens = _jobDataLens;
this._lastGroupsSet = _lastGroupsSet;
/**
* Subscribe for consumer group ids changes
*/
this._groups.subscribe((consumers) => {
this._lastGroupsSet = consumers;
});
// subscribe source processing once groups initialized
this._groups.onMembersInit(() => {
// group members list initialized (loaded from db), can now process source jobs
this._source.process((job, cb) => {
/**
* Dispatch messages from source {@Link Queue} to out {@Link NamedQueue} using ConsumerGroupId as QueueTopic
*/
this._lastGroupsSet.forEach((groupId) => {
if (groupId) {
this._out.add(QueueTopic(groupId), this._jobDataLens(job));
}
});
cb();
});
});
}
/**
* Create new job
* @param {Object} data
* @returns {Job}
*/
add(data) {
this._source.add(data);
}
/**
* Subscribe for processing using given groupId
*
* All subscribers using same groupId will split messages processing
* @param {ConsumerGroupId} groupId
* @param {ProcessCallback<Job>} fn
* @param {number} n
*/
process(groupId, fn, n) {
/**
* Register new consumer group so sources can dispatch messages for new group
*/
this._groups.add(groupId);
/**
* Attach handler itself for processing
*/
this._out.process(QueueTopic(groupId), fn, n);
}
/**
* Removes consumer group for current topic
* Use this for cleanup, replace process(groupId) with removeGroup(groupId), deploy for a while
*/
removeGroup(groupId) {
this._groups.remove(groupId);
return this;
}
}
exports.MultiConsumerQueueImpl = MultiConsumerQueueImpl;
/**
* EventBus implementation
*/
class EventBusImpl {
/**
* @param _buildQueue MultiConsumerQueue builder function
*/
constructor(_buildQueue) {
this._buildQueue = _buildQueue;
this._queueMap = immutable_1.Map();
}
topic(topic) {
/**
* Create queue for given topic name and store the reference
*/
if (!this._queueMap.has(topic)) {
this._queueMap = this._queueMap.set(topic, this._buildQueue(topic));
}
return this._queueMap.get(topic);
}
}
exports.EventBusImpl = EventBusImpl;
//# sourceMappingURL=index.js.map