event-driven
Version:
makes building event-driven-architecture easy
137 lines (136 loc) • 6.89 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 __asyncValues = (this && this.__asyncValues) || function (o) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
var m = o[Symbol.asyncIterator], i;
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SubscriberPullGroup = void 0;
const backend_1 = require("../backend");
const nats_1 = require("nats");
const __1 = require("..");
const common_1 = require("./common");
const getSubsDetails = (subscription) => {
if (typeof subscription === 'function') {
const eventHandler = subscription;
return { eventHandler, batchCustom: undefined, expiresCustom: undefined, groupBy: undefined };
}
else {
const [eventHandler, { batch: batchCustom, expires: expiresCustom, groupBy }] = subscription;
return { eventHandler, batchCustom, expiresCustom, groupBy };
}
};
const SubscriberPullGroup = (config) => {
return ({ subject, subscriptions, }) => __awaiter(void 0, void 0, void 0, function* () {
for (let i = 0; i < subscriptions.length; i++) {
const subscription = subscriptions[i];
const { eventHandler, groupBy, batchCustom, expiresCustom } = getSubsDetails(subscription);
const durableName = common_1.getDurableName(config.clientGroup, subject, i, 'GROUP');
try {
let msgs = [];
const opts = nats_1.consumerOpts();
opts.ackWait(30000);
opts.manualAck();
opts.durable(durableName);
opts.maxAckPending(500);
const psub = yield config.js.pullSubscribe(subject, opts);
(() => __awaiter(void 0, void 0, void 0, function* () {
var e_1, _a;
try {
for (var psub_1 = __asyncValues(psub), psub_1_1; psub_1_1 = yield psub_1.next(), !psub_1_1.done;) {
const m = psub_1_1.value;
msgs.push(m);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (psub_1_1 && !psub_1_1.done && (_a = psub_1.return)) yield _a.call(psub_1);
}
finally { if (e_1) throw e_1.error; }
}
}))();
setInterval(() => {
if (msgs.length > 0) {
processEvents({
msgs: msgs.splice(0, 10000),
maxRetryCount: __1._maxRetryCount,
js: config.js,
clientGroup: config.clientGroup,
eventHandler,
durableName,
subject,
eventHandlerOrder: i,
showError: __1._showError,
//if no groupBy condition is provided group all events
groupBy: groupBy !== null && groupBy !== void 0 ? groupBy : (() => 1),
showProcessTimeWarning: __1._showProcessTimeWarning,
});
}
}, 100);
const batch = batchCustom !== null && batchCustom !== void 0 ? batchCustom : config.batch;
const expires = expiresCustom !== null && expiresCustom !== void 0 ? expiresCustom : config.expires;
psub.pull({ batch, expires });
setInterval(() => psub.pull({ batch, expires }), expires);
}
catch (err) {
console.error(`clientGroup: ${config.clientGroup}, index: ${i}, subject: ${subject}`);
throw err;
}
}
});
};
exports.SubscriberPullGroup = SubscriberPullGroup;
const processEvents = ({ msgs, maxRetryCount, js, clientGroup, eventHandler, durableName, subject, eventHandlerOrder, showError, showProcessTimeWarning, groupBy, }) => __awaiter(void 0, void 0, void 0, function* () {
const msgFilter = common_1.filterConvertedMsgs(clientGroup, subject, eventHandlerOrder, showError, durableName, maxRetryCount);
const events = msgs.map(common_1.convertJsMsg).filter(msgFilter);
const groupedEvents = common_1.groupByFn(events, (e) => groupBy(e.msgData)).map((events) => {
const parentIds = events.map((event) => event.parentId);
const ack = () => {
events.map((event) => event.jsMsg.ack());
};
const nak = (delay) => {
events.map((event) => event.jsMsg.nak(delay));
};
const fail = backend_1.getFail({
parentIds,
ack,
nak,
durableName,
clientGroup,
subject,
eventHandlerOrder,
maxRetryCount,
showError,
});
return {
inputs: events.map((event) => event.msgData),
ack,
fail,
config: { js, clientGroup, parentIds, durableName },
};
});
try {
let start = new Date();
yield eventHandler(groupedEvents);
let diff = new Date().getTime() - start.getTime();
//TODO sstore process time
if (showProcessTimeWarning && showProcessTimeWarning < diff)
console.log('\x1b[33m%s\x1b[0m', `[WARNING-TIME] ${diff / 1000}s, durableName: ${durableName}`);
}
catch (error) {
//TODO store unhandled errors
console.error('\x1b[31m%s\x1b[0m', `UNHANDLED SUBSCRIPTION BATCH ERRROR(${durableName})`, error);
}
});