UNPKG

@sailboat-computer/data-storage

Version:

Shared data storage library for sailboat computer v3

220 lines 6.75 kB
"use strict"; /** * Batch manager implementation */ Object.defineProperty(exports, "__esModule", { value: true }); exports.createBatchManager = exports.BatchManagerImpl = void 0; const types_1 = require("../types"); const errors_1 = require("../utils/errors"); /** * Default batch configuration */ const DEFAULT_CONFIG = { timeBased: { enabled: true, intervalMs: 30000 // 30 seconds }, sizeBased: { enabled: true, maxBatchSize: 100 }, priorityOverride: true, maxRetries: 3, retryDelayMs: 1000 }; /** * Batch manager implementation */ class BatchManagerImpl { /** * Create a new batch manager * * @param provider - Storage provider */ constructor(provider) { this.provider = provider; this.batches = new Map(); this.initialized = false; this.stopped = false; this.stats = { pendingItems: 0, lastFlush: undefined, averageBatchSize: 0, totalBatches: 0, failedBatches: 0 }; this.config = DEFAULT_CONFIG; } /** * Initialize the batch manager * * @param config - Batch configuration */ initialize(config) { if (this.initialized) { return; } this.config = { ...DEFAULT_CONFIG, ...config }; // Start time-based flushing if enabled if (this.config.timeBased.enabled) { this.startTimedFlush(); } this.initialized = true; console.log('Batch manager initialized'); } /** * Add data to batch * * @param data - Data to add * @param metadata - Data metadata * @param priority - Batch priority */ addToBatch(data, metadata, priority = types_1.BatchPriority.NORMAL) { this.ensureInitialized(); // Get category key const categoryKey = metadata.category; // Get or create batch for category if (!this.batches.has(categoryKey)) { this.batches.set(categoryKey, []); } const batch = this.batches.get(categoryKey); // Add item to batch batch.push({ data, metadata, priority }); this.stats.pendingItems++; // Check if we should flush due to priority if (this.config.priorityOverride && priority === types_1.BatchPriority.CRITICAL) { this.flushCategory(categoryKey); return; } // Check if we should flush due to size if (this.config.sizeBased.enabled && batch.length >= this.config.sizeBased.maxBatchSize) { this.flushCategory(categoryKey); } } /** * Flush all batches */ async flush() { this.ensureInitialized(); try { // Get all category keys const categories = Array.from(this.batches.keys()); // Flush each category await Promise.all(categories.map(category => this.flushCategory(category))); // Update stats this.stats.lastFlush = new Date(); } catch (error) { console.error('Failed to flush batches:', error); throw new errors_1.StorageError(errors_1.StorageErrorCode.STORE_FAILED, 'Failed to flush batches', { error }); } } /** * Get batch status * * @returns Batch status */ getBatchStatus() { return { pendingItems: this.stats.pendingItems, lastFlush: this.stats.lastFlush, averageBatchSize: this.stats.averageBatchSize, totalBatches: this.stats.totalBatches, failedBatches: this.stats.failedBatches }; } /** * Stop the batch manager */ stop() { if (this.stopped) { return; } // Stop timed flush if (this.flushTimer) { clearInterval(this.flushTimer); this.flushTimer = undefined; } this.stopped = true; console.log('Batch manager stopped'); } /** * Start timed flush */ startTimedFlush() { this.flushTimer = setInterval(() => { this.flush().catch(error => { console.error('Error during timed flush:', error); }); }, this.config.timeBased.intervalMs); } /** * Flush a specific category * * @param category - Category to flush */ async flushCategory(category) { const batch = this.batches.get(category); if (!batch || batch.length === 0) { return; } try { // Sort batch by priority batch.sort((a, b) => { const priorityOrder = { 'batch_critical': 0, 'batch_high': 1, 'batch_normal': 2, 'batch_low': 3 }; return priorityOrder[a.priority] - priorityOrder[b.priority]; }); // Prepare items for storage const items = batch.map(item => ({ data: item.data, metadata: item.metadata })); // Store batch await this.provider.storeBatch(items); // Update stats this.stats.totalBatches++; this.stats.pendingItems -= batch.length; this.stats.averageBatchSize = (this.stats.averageBatchSize * (this.stats.totalBatches - 1) + batch.length) / this.stats.totalBatches; // Clear batch this.batches.set(category, []); } catch (error) { console.error(`Failed to flush batch for category ${category}:`, error); this.stats.failedBatches++; throw new errors_1.StorageError(errors_1.StorageErrorCode.STORE_FAILED, `Failed to flush batch for category ${category}`, { category, error }); } } /** * Ensure batch manager is initialized * * @throws StorageError if not initialized */ ensureInitialized() { if (!this.initialized) { throw new errors_1.StorageError(errors_1.StorageErrorCode.SYSTEM_ERROR, 'Batch manager not initialized', {}); } if (this.stopped) { throw new errors_1.StorageError(errors_1.StorageErrorCode.SYSTEM_ERROR, 'Batch manager has been stopped', {}); } } } exports.BatchManagerImpl = BatchManagerImpl; /** * Create a new batch manager * * @param provider - Storage provider * @returns Batch manager */ function createBatchManager(provider) { return new BatchManagerImpl(provider); } exports.createBatchManager = createBatchManager; //# sourceMappingURL=manager.js.map