UNPKG

polyv-live-cli

Version:

CLI tool for managing PolyV live streaming services.

355 lines 12.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BatchRequestManager = void 0; const events_1 = require("events"); class BatchRequestManager extends events_1.EventEmitter { constructor(config = {}) { super(); this.pendingRequests = new Map(); this.activeBatches = new Map(); this.batchTimers = new Map(); this.requestIdCounter = 0; this.batchIdCounter = 0; this.isRunning = false; this.config = { maxBatchSize: 20, maxWaitTime: 1000, minBatchInterval: 100, enableIntelligentBatching: true, maxConcurrentBatches: 5, retryAttempts: 3, retryDelay: 1000, ...config, }; this.stats = { totalBatches: 0, totalRequests: 0, averageBatchSize: 0, averageProcessingTime: 0, successRate: 0, requestsPerSecond: 0, pendingRequests: 0, activeBatches: 0, }; this.setupPeriodicBatchProcessing(); } start() { if (this.isRunning) { return; } this.isRunning = true; this.emit('started', { timestamp: Date.now(), config: this.config, }); } stop() { if (!this.isRunning) { return; } this.isRunning = false; for (const timer of this.batchTimers.values()) { clearTimeout(timer); } this.batchTimers.clear(); if (this.periodicProcessTimer) { clearInterval(this.periodicProcessTimer); this.periodicProcessTimer = undefined; } for (const request of this.pendingRequests.values()) { request.reject(new Error('Batch request manager stopped')); } this.pendingRequests.clear(); this.emit('stopped', { timestamp: Date.now(), stats: this.getStats(), }); } addRequest(method, url, params = {}, body, options = {}) { if (!this.isRunning) { return Promise.reject(new Error('Batch request manager is not running')); } const requestId = this.generateRequestId(); const timestamp = Date.now(); return new Promise((resolve, reject) => { const request = { id: requestId, method: method.toUpperCase(), url, params, body, priority: options.priority || 'medium', timestamp, resolve, reject, ...(options.headers && { headers: options.headers }), ...(options.timeout && { timeout: options.timeout }), }; this.pendingRequests.set(requestId, request); this.stats.pendingRequests = this.pendingRequests.size; this.emit('requestAdded', { requestId, method, url, priority: request.priority, timestamp, }); this.checkBatchProcessingConditions(); }); } getStats() { return { ...this.stats }; } getPendingRequests() { return Array.from(this.pendingRequests.values()).map(request => ({ id: request.id, method: request.method, url: request.url, priority: request.priority, timestamp: request.timestamp, })); } async flushPendingRequests() { if (this.pendingRequests.size === 0) { return; } const requests = Array.from(this.pendingRequests.values()); this.pendingRequests.clear(); this.stats.pendingRequests = 0; await this.processBatch(requests); } updateConfig(newConfig) { this.config = { ...this.config, ...newConfig }; this.emit('configUpdated', { config: this.config, timestamp: Date.now(), }); } resetStats() { this.stats = { totalBatches: 0, totalRequests: 0, averageBatchSize: 0, averageProcessingTime: 0, successRate: 0, requestsPerSecond: 0, pendingRequests: this.pendingRequests.size, activeBatches: this.activeBatches.size, }; this.emit('statsReset', { timestamp: Date.now(), }); } generateRequestId() { return `req_${++this.requestIdCounter}_${Date.now()}`; } generateBatchId() { return `batch_${++this.batchIdCounter}_${Date.now()}`; } checkBatchProcessingConditions() { const pendingCount = this.pendingRequests.size; const activeCount = this.activeBatches.size; if (pendingCount >= this.config.maxBatchSize || activeCount < this.config.maxConcurrentBatches) { this.scheduleImmediateBatchProcessing(); } } scheduleImmediateBatchProcessing() { setTimeout(() => { if (this.pendingRequests.size > 0) { this.processNextBatch(); } }, 0); } setupPeriodicBatchProcessing() { const processInterval = Math.max(this.config.maxWaitTime, this.config.minBatchInterval); this.periodicProcessTimer = setInterval(() => { if (this.isRunning && this.pendingRequests.size > 0) { this.processNextBatch(); } }, processInterval); } async processNextBatch() { if (this.activeBatches.size >= this.config.maxConcurrentBatches) { return; } const batchRequests = this.selectRequestsForBatch(); if (batchRequests.length === 0) { return; } for (const request of batchRequests) { this.pendingRequests.delete(request.id); } this.stats.pendingRequests = this.pendingRequests.size; await this.processBatch(batchRequests); } selectRequestsForBatch() { const allRequests = Array.from(this.pendingRequests.values()); if (allRequests.length === 0) { return []; } allRequests.sort((a, b) => { const priorityOrder = { high: 0, medium: 1, low: 2 }; const priorityDiff = priorityOrder[a.priority] - priorityOrder[b.priority]; if (priorityDiff !== 0) { return priorityDiff; } return a.timestamp - b.timestamp; }); let batchRequests = []; if (this.config.enableIntelligentBatching) { batchRequests = this.selectIntelligentBatch(allRequests); } else { batchRequests = allRequests.slice(0, this.config.maxBatchSize); } return batchRequests; } selectIntelligentBatch(requests) { const batch = []; const usedUrls = new Set(); const maxSize = this.config.maxBatchSize; for (const request of requests) { if (request.priority === 'high' && batch.length < maxSize) { batch.push(request); usedUrls.add(request.url); } } for (const request of requests) { if (batch.length >= maxSize) { break; } if (batch.includes(request)) { continue; } const hasSimilarRequest = batch.some(batchedRequest => batchedRequest.url === request.url || batchedRequest.method === request.method); if (hasSimilarRequest || batch.length < maxSize / 2) { batch.push(request); usedUrls.add(request.url); } } for (const request of requests) { if (batch.length >= maxSize) { break; } if (!batch.includes(request)) { batch.push(request); } } return batch; } async processBatch(requests) { if (requests.length === 0) { return; } const batchId = this.generateBatchId(); const startTime = Date.now(); this.activeBatches.set(batchId, requests); this.stats.activeBatches = this.activeBatches.size; this.emit('batchStarted', { batchId, requestCount: requests.length, timestamp: startTime, }); try { const results = await this.executeBatch(batchId, requests); const endTime = Date.now(); const processingTime = endTime - startTime; this.updateBatchStats(requests.length, results, processingTime); const batchResult = { batchId, requestCount: requests.length, successCount: results.filter(r => r.success).length, failureCount: results.filter(r => !r.success).length, processingTime, results, }; this.emit('batchCompleted', { batchId, result: batchResult, timestamp: endTime, }); for (const result of results) { const request = requests.find(r => r.id === result.requestId); if (request) { if (result.success) { request.resolve(result.data); } else { request.reject(result.error); } } } } catch (error) { this.emit('batchError', { batchId, error, timestamp: Date.now(), }); for (const request of requests) { request.reject(error); } } finally { this.activeBatches.delete(batchId); this.stats.activeBatches = this.activeBatches.size; } } async executeBatch(_batchId, requests) { const results = []; const executeRequest = async (request) => { const requestStartTime = Date.now(); try { const response = await this.executeIndividualRequest(request); const responseTime = Date.now() - requestStartTime; results.push({ requestId: request.id, success: true, data: response, responseTime, }); } catch (error) { const responseTime = Date.now() - requestStartTime; results.push({ requestId: request.id, success: false, error, responseTime, }); } }; await Promise.all(requests.map(executeRequest)); return results; } async executeIndividualRequest(request) { const delay = 50; await new Promise(resolve => setTimeout(resolve, delay)); if (request.url.includes('simulate-failure')) { throw new Error(`Request failed: ${request.method} ${request.url}`); } return { id: request.id, method: request.method, url: request.url, params: request.params, body: request.body, timestamp: Date.now(), data: `Response for ${request.method} ${request.url}`, }; } updateBatchStats(requestCount, results, processingTime) { this.stats.totalBatches++; this.stats.totalRequests += requestCount; this.stats.averageBatchSize = this.stats.totalRequests / this.stats.totalBatches; this.stats.averageProcessingTime = ((this.stats.averageProcessingTime * (this.stats.totalBatches - 1)) + processingTime) / this.stats.totalBatches; const successCount = results.filter(r => r.success).length; const totalSuccessful = (this.stats.successRate * (this.stats.totalRequests - requestCount)) + successCount; this.stats.successRate = totalSuccessful / this.stats.totalRequests; this.stats.requestsPerSecond = requestCount / (processingTime / 1000); } } exports.BatchRequestManager = BatchRequestManager; //# sourceMappingURL=batch-request-manager.js.map