UNPKG

@aimee-blue/ab-service-kit

Version:
177 lines (141 loc) 5.85 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.prepareTopics = prepareTopics; exports.publish = publish; exports.subscribe = subscribe; exports.getTopic = exports.pubsubClient = void 0; var PubSub = _interopRequireWildcard(require("@google-cloud/pubsub")); var _rxjs = require("rxjs"); var _operators = require("rxjs/operators"); var _app = require("../app"); var _os = require("os"); var _isTest = require("../isTest"); var _registerError = require("../registerError"); var _logging = require("../logging"); var _uuid = require("../uuid"); function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; } function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } let initializedClient = null; const pubsubClient = () => { return initializedClient || (initializedClient = new PubSub.PubSub()); }; exports.pubsubClient = pubsubClient; const topicMap = new Map(); const retrySettings = { retryCodes: [10, // 'ABORTED' 1, // 'CANCELLED', 4, // 'DEADLINE_EXCEEDED' 13, // 'INTERNAL' 8, // 'RESOURCE_EXHAUSTED' 14, // 'UNAVAILABLE' 2 // 'UNKNOWN' ], backoffSettings: { initialRetryDelayMillis: 5, retryDelayMultiplier: 2, maxRetryDelayMillis: 60000, initialRpcTimeoutMillis: 10000, rpcTimeoutMultiplier: 1.0, maxRpcTimeoutMillis: 10000, totalTimeoutMillis: 10000 } }; const addTopicToMap = topic => { const topicWithOpts = pubsubClient().topic(topic); topicWithOpts.setPublishOptions({ batching: { maxMessages: 1, maxMilliseconds: 1, maxBytes: 1 }, gaxOpts: { retry: retrySettings } }); topicMap.set(topic, topicWithOpts); return topicMap.get(topic); }; const getTopic = topic => { const topicPublisher = topicMap.has(topic) ? topicMap.get(topic) : addTopicToMap(topic); if (!topicPublisher) { return addTopicToMap(topic); } return topicPublisher; }; exports.getTopic = getTopic; async function prepareTopics(topics) { topics.forEach(topic => { addTopicToMap(topic); }); } const TIMEOUT_ERROR = 'Retry total timeout exceeded before any response'; async function publish(topic, data, logger = (0, _logging.defaultBasicLogger)()) { const topicPublisher = getTopic(topic); topicPublisher.publish(Buffer.from(JSON.stringify(data), 'utf8'), (err, mesId) => { if (err) { (0, _registerError.registerError)(err); if (err.message.includes(TIMEOUT_ERROR)) { topicMap.delete(topic); } logger.error(`💥 Error when publishing to topic ${topic} ${mesId ? `with message ${mesId}` : ''}`, err); } }); } const subscriptionNamesByTopic = new Map(); async function createTopicAndSubscription(topic, fullName, options) { const shortName = fullName.replace('@aimee-blue/', ''); const genName = (0, _isTest.isDevBuild)() ? `${shortName}-${String(process.env.USER)}` : `${shortName}-${(0, _uuid.uuid)()}`; const lastName = subscriptionNamesByTopic.get(topic); const { autoCreateTopic, subscriptionName, autoCreateSubscription, subscriptionOptions, ...subOpts } = { autoCreateTopic: true, subscriptionName: lastName || genName, autoCreateSubscription: true, subscriptionOptions: undefined, ...options }; const topicPublisher = getTopic(topic); if (autoCreateTopic && !lastName) { const [topicExists] = await topicPublisher.exists(); if (!topicExists) { await topicPublisher.create(); } } const subscription = topicPublisher.subscription(subscriptionName, subOpts); if (autoCreateSubscription && !lastName) { const [exists] = await subscription.exists(); if (!exists) { await subscription.create(subscriptionOptions); } } // if success, then remember: if (!subscriptionNamesByTopic.get(topic)) { subscriptionNamesByTopic.set(topic, subscriptionName); } return subscription; } function subscribe(topic, options, optLogger) { return (0, _rxjs.defer)(() => (0, _rxjs.from)((0, _app.appName)())).pipe((0, _operators.switchMap)(name => createTopicAndSubscription(topic, name, options)), (0, _operators.switchMap)(subscription => new _rxjs.Observable(subscriber => { const name = subscription.name; const logger = optLogger || (0, _logging.defaultBasicLogger)(); logger.log(`${_os.EOL}🎬 Subscribing to topic "${topic}" with subscription "${name}"`, _os.EOL); subscriber.add((0, _rxjs.merge)((0, _rxjs.fromEvent)(subscription, 'message'), (0, _rxjs.fromEvent)(subscription, 'error').pipe((0, _operators.map)(err => { throw err; }), (0, _operators.ignoreElements)())).subscribe(subscriber)); subscriber.add(() => { subscription.close().then(() => { logger.log(`${_os.EOL}🏁 Unsubscribed from "${subscription.name}"`, _os.EOL); }).catch(err => { (0, _registerError.registerError)(err); logger.error(`${_os.EOL}💥 Error when unsubscribing from "${subscription.name}"`, err, _os.EOL); }); }); }))); } //# sourceMappingURL=pubsub.js.map