UNPKG

ali-ons-sdk

Version:

Aliyun Open Notification Service Client

180 lines (159 loc) 4.5 kB
'use strict'; const fs = require('fs'); const path = require('path'); const osenv = require('osenv'); const mkdirp = require('mkdirp'); const is = require('is-type-of'); const Base = require('sdk-base'); const ReadOffsetType = require('./read_offset_type'); const localOffsetStoreDir = path.join(osenv.home(), '.rocketmq_offsets_node'); class LocalFileOffsetStore extends Base { /** * 消费进度存储到Consumer本地 * @param {MQClient} mqClient - * @param {String} groupName 分组名 * @contructor */ constructor(mqClient, groupName) { super(); this.mqClient = mqClient; this.groupName = groupName; this.offsetTable = new Map(); this.storePath = path.join(localOffsetStoreDir, mqClient.clientId, groupName, 'offsets.json'); mkdirp.sync(path.dirname(this.storePath)); } get logger() { return this.mqClient.logger; } /** * 加载Offset */ async load() { const data = await this.readLocalOffset(); if (data && data.offsetTable) { for (const key in data.offsetTable) { if (is.number(data.offsetTable[key])) { this.offsetTable.set(key, data.offsetTable[key]); } } } } /** * 更新消费进度,存储到内存 * @param {MessageQueue} messageQueue - * @param {Number} offset 新的进度 * @param {Boolean} increaseOnly 是否强制覆盖 * @return {void} */ updateOffset(messageQueue, offset, increaseOnly) { increaseOnly = increaseOnly || false; if (!messageQueue) { return; } let prev = -1; if (this.offsetTable.has(messageQueue.key)) { prev = this.offsetTable.get(messageQueue.key); } if (prev >= offset && increaseOnly) { return; } this.offsetTable.set(messageQueue.key, offset); this.logger.info('[mq:LocalFileOffsetStore] update offset for messageQueue: %s, current offset: %d, prev offset: %s, increaseOnly: %s', messageQueue.key, offset, prev, increaseOnly); } /** * 从本地缓存读取消费进度 * @param {MessageQueue} messageQueue - * @param {String} type 消费类型(从哪里开始消费) * @param {Function} callback 回调函数 * @return {void} */ async readOffset(messageQueue, type) { if (!messageQueue) { return -1; } switch (type) { case ReadOffsetType.MEMORY_FIRST_THEN_STORE: case ReadOffsetType.READ_FROM_MEMORY: { const offset = this.offsetTable.get(messageQueue.key); if (!is.nullOrUndefined(offset)) { return offset; } break; } case ReadOffsetType.READ_FROM_STORE: { const data = await this.readLocalOffset(); if (data && data.offsetTable) { const offset = data.offsetTable[messageQueue.key]; if (is.number(offset)) { this.updateOffset(messageQueue, offset, false); return offset; } } break; } default: break; } return -1; } /** * 持久化全部消费进度,可能持久化本地或者远端Broker * @param {Array} mqs - * @return {void} */ async persistAll(mqs) { if (mqs && mqs.length) { const data = { offsetTable: {}, }; const newTable = new Map(); for (const messageQueue of mqs) { const offset = this.offsetTable.get(messageQueue.key) || -1; data.offsetTable[messageQueue.key] = offset; newTable.set(messageQueue.key, offset); } this.offsetTable = newTable; fs.writeFileSync(this.storePath, JSON.stringify(data)); } } /* eslint-disable no-empty-function */ /** * 持久化消费进度 * @return {void} */ async persist() {} /* eslint-enable no-empty-function */ /** * 删除不必要的MessageQueue offset * @param {Object} messageQueue 消息队列 * @return {void} */ removeOffset(messageQueue) { if (messageQueue) { this.offsetTable.delete(messageQueue.key); } } /** * 从本地文件读消费进度 * @return {void} */ async readLocalOffset() { if (!fs.existsSync(this.storePath)) { return null; } const content = fs.readFileSync(this.storePath); if (!content) { return null; } try { return JSON.parse(content.toString()); } catch (e) { e.message = 'readLocalOffset() failed' + e.message; this.emit('error', e); return null; } } } module.exports = LocalFileOffsetStore;