UNPKG

@bugsnag/core-performance

Version:
107 lines (104 loc) 3.96 kB
import { runSpanEndCallbacks } from './span.js'; class BatchProcessor { constructor(delivery, configuration, retryQueue, sampler, probabilityManager, encoder) { this.spans = []; this.timeout = null; this.flushQueue = Promise.resolve(); this.delivery = delivery; this.configuration = configuration; this.retryQueue = retryQueue; this.sampler = sampler; this.probabilityManager = probabilityManager; this.encoder = encoder; this.flush = this.flush.bind(this); } stop() { if (this.timeout !== null) { clearTimeout(this.timeout); this.timeout = null; } } start() { this.stop(); this.timeout = setTimeout(this.flush, this.configuration.batchInactivityTimeoutMs); } add(span) { if (this.configuration.enabledReleaseStages && !this.configuration.enabledReleaseStages.includes(this.configuration.releaseStage)) { return; } this.spans.push(span); if (this.spans.length >= this.configuration.maximumBatchSize) { this.flush(); } else { this.start(); } } async flush() { this.stop(); this.flushQueue = this.flushQueue.then(async () => { const batch = await this.prepareBatch(); // we either had nothing in the batch originally or all spans were discarded if (!batch) { return; } const payload = await this.encoder.encode(batch); const batchTime = Date.now(); try { const response = await this.delivery.send(payload); if (response.samplingProbability !== undefined) { this.probabilityManager.setProbability(response.samplingProbability); } switch (response.state) { case 'success': this.retryQueue.flush(); break; case 'failure-discard': this.configuration.logger.warn('delivery failed'); break; case 'failure-retryable': this.configuration.logger.info('delivery failed, adding to retry queue'); this.retryQueue.add(payload, batchTime); break; default: response.state; } } catch (err) { this.configuration.logger.warn('delivery failed'); } }); await this.flushQueue; } async prepareBatch() { if (this.spans.length === 0) { return; } // ensure we have a fresh probability value before building the batch await this.probabilityManager.ensureFreshProbability(); // update sampling values if necessary and re-sample const batch = []; const probability = this.sampler.spanProbability; for (const span of this.spans) { if (span.samplingProbability.raw > probability.raw) { span.samplingProbability = probability; } if (this.sampler.sample(span)) { // Run any callbacks that have been registered before batching // as callbacks could cause the span to be discarded const shouldAddToBatch = await runSpanEndCallbacks(span, this.configuration.logger, this.configuration.onSpanEnd); if (shouldAddToBatch) batch.push(span); } } // clear out the current batch so we're ready to start a new one this.spans = []; // if every span was discarded there's nothing to send if (batch.length === 0) { return; } return batch; } } export { BatchProcessor };