perf(wai): 使用队列处理消息事件
parent
1cd09cdfdd
commit
e4ecab76d8
@ -0,0 +1,68 @@
|
||||
'use strict';
|
||||
|
||||
const { default: pRetry } = require('@fullstax/p-retry');
|
||||
|
||||
/**
|
||||
* Creates an async queue processor.
|
||||
* 不同 itemId 的数据并发处理
|
||||
* 每个 itemId 的数据有序地仅处理一个, 先进先出
|
||||
* @param {Function} processItemFn - The function to process each item in the queue.
|
||||
* @param {Object} [options] - Options for the queue processor.
|
||||
* @param {Object} [options.retryOptions] - Options for retrying failed items.
|
||||
* @param {number} [options.retryOptions.retries] - Number of retries for failed items.
|
||||
* @returns {Object} - An object with an enqueue method to add items tothe queue.
|
||||
*/
|
||||
async function createAsyncQueueProcessor(processItemFn, options = {}) {
|
||||
if (typeof processItemFn !== 'function') {
|
||||
throw new Error('processItemFn must be a function');
|
||||
}
|
||||
|
||||
const { retryOptions = { retries: 0 } } = options;
|
||||
const queues = new Map();
|
||||
const processing = new Map();
|
||||
|
||||
async function processQueue(itemId) {
|
||||
if (processing.get(itemId)) {
|
||||
return; // processing
|
||||
}
|
||||
|
||||
processing.set(itemId, true);
|
||||
|
||||
try {
|
||||
const queue = queues.get(itemId);
|
||||
if (!queue) return;
|
||||
|
||||
while (queue.length > 0) {
|
||||
const item = queue.shift();
|
||||
try {
|
||||
if (retryOptions.retries > 0) {
|
||||
await pRetry(async () => {
|
||||
await processItemFn(item);
|
||||
}, retryOptions);
|
||||
} else {
|
||||
await processItemFn(item);
|
||||
}
|
||||
} catch (itemError) {
|
||||
console.error(`Error processing item ${JSON.stringify(item)}:\n`, itemError);
|
||||
// Handle error (e.g., retry, log, DLQ)
|
||||
}
|
||||
}
|
||||
queues.delete(itemId); // Clean up empty queue
|
||||
} finally {
|
||||
processing.set(itemId, false);
|
||||
}
|
||||
}
|
||||
|
||||
function enqueue(itemId, itemData) {
|
||||
if (!queues.has(itemId)) {
|
||||
queues.set(itemId, []);
|
||||
}
|
||||
|
||||
queues.get(itemId).push(itemData);
|
||||
processQueue(itemId);
|
||||
}
|
||||
|
||||
return { enqueue };
|
||||
}
|
||||
|
||||
module.exports = createAsyncQueueProcessor;
|
Loading…
Reference in New Issue