UNPKG

synapse-storage

Version:

Набор инструментов для управления состоянием и апи-запросами

108 lines (106 loc) 4.77 kB
// storage-batching.middleware.ts - ИСПРАВЛЕННАЯ ВЕРСИЯ const batchingMiddleware = (options = {})=>{ const batchSize = options.batchSize ?? 10; const batchDelay = options.batchDelay ?? 10 // Уменьшил для более быстрого батчинга ; const queues = new Map(); const timeouts = new Map(); const shouldBatch = (action)=>{ return action.type === 'set' || action.type === 'update'; }; const getSegmentKey = (action)=>{ return `${action.type}_${action.key?.toString() || 'default'}`; }; const mergeActions = (actions)=>{ const merged = new Map(); // Группируем по ключу и оставляем только последнее значение for (const action of actions){ const key = `${action.type}_${action.key?.toString() || 'default'}`; merged.set(key, action); // Последнее действие перезаписывает предыдущие } return Array.from(merged.values()); }; const clearTimeout = (segment)=>{ const timeout = timeouts.get(segment); if (timeout) { globalThis.clearTimeout(timeout); timeouts.delete(segment); } }; const setTimeout = (segment, callback)=>{ const timeout = globalThis.setTimeout(callback, batchDelay); timeouts.set(segment, timeout); }; const processBatch = async (segment, api, next)=>{ const queue = queues.get(segment); if (!queue || queue.length === 0) return; // Очищаем очередь и таймер queues.delete(segment); clearTimeout(segment); try { // Объединяем действия const actions = queue.map((item)=>item.action); const mergedActions = mergeActions(actions); // Выполняем только merged actions for (const mergedAction of mergedActions){ try { // Выполняем merged действие const result = await next(mergedAction); // Находим все queue items, которые соответствуют этому merged action const matchingItems = queue.filter((item)=>item.action.type === mergedAction.type && item.action.key?.toString() === mergedAction.key?.toString()); // Все соответствующие items получают результат merged операции matchingItems.forEach((item)=>item.resolve(result)); } catch (error) { // В случае ошибки отклоняем соответствующие промисы const matchingItems = queue.filter((item)=>item.action.type === mergedAction.type && item.action.key?.toString() === mergedAction.key?.toString()); matchingItems.forEach((item)=>item.reject(error)); } } } catch (error) { // В случае общей ошибки отклоняем все промисы queue.forEach((item)=>item.reject(error)); } }; const addToQueue = async (action, api, next)=>{ return new Promise((resolve, reject)=>{ const segment = getSegmentKey(action); let queue = queues.get(segment); if (!queue) { queue = []; queues.set(segment, queue); } queue.push({ action, resolve, reject, timestamp: Date.now() }); clearTimeout(segment); if (queue.length >= batchSize) { // Немедленно обрабатываем батч queueMicrotask(()=>processBatch(segment, api, next)); } else { // Устанавливаем таймер setTimeout(segment, ()=>processBatch(segment, api, next)); } }); }; return { name: 'batching', setup: ()=>{}, cleanup: async ()=>{ // Очищаем таймеры timeouts.forEach((timeout)=>globalThis.clearTimeout(timeout)); timeouts.clear(); queues.clear(); }, reducer: (api)=>(next)=>async (action)=>{ if (!shouldBatch(action)) { return next(action); } return addToQueue(action, api, next); } }; }; export { batchingMiddleware }; //# sourceMappingURL=storage-batching.middleware.js.map