@bugsnag/core-performance
Version:
Core performance client
107 lines (104 loc) • 3.96 kB
JavaScript
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 };