@backstage/plugin-catalog-backend
Version:
The Backstage backend plugin that provides the Backstage catalog
93 lines (89 loc) • 2.83 kB
JavaScript
var opentelemetry = require('../util/opentelemetry.cjs.js');
var api = require('@opentelemetry/api');
const DEFAULT_POLLING_INTERVAL_MS = 1e3;
const tracer = api.trace.getTracer(opentelemetry.TRACER_ID);
function startTaskPipeline(options) {
const {
loadTasks,
processTask,
lowWatermark,
highWatermark,
pollingIntervalMs = DEFAULT_POLLING_INTERVAL_MS
} = options;
if (lowWatermark >= highWatermark) {
throw new Error("lowWatermark must be lower than highWatermark");
}
const state = { inFlightCount: 0 };
const abortController = new AbortController();
const abortSignal = abortController.signal;
const barrier = createBarrier({
waitTimeoutMillis: pollingIntervalMs,
signal: abortSignal
});
async function pipelineLoop() {
while (!abortSignal.aborted) {
if (state.inFlightCount <= lowWatermark) {
await opentelemetry.withActiveSpan(tracer, "TaskPipelineLoop", async (span) => {
const loadCount = highWatermark - state.inFlightCount;
const loadedItems = await Promise.resolve().then(() => loadTasks(loadCount)).catch(() => {
return [];
});
span.setAttribute("itemCount", loadedItems.length);
if (loadedItems.length && !abortSignal.aborted) {
state.inFlightCount += loadedItems.length;
for (const item of loadedItems) {
Promise.resolve().then(() => processTask(item)).catch(() => {
}).finally(() => {
state.inFlightCount -= 1;
barrier.release();
});
}
}
});
}
await barrier.wait();
}
}
pipelineLoop().catch((error) => {
throw new Error(`Unexpected error in processing pipeline loop`, error);
});
return () => {
abortController.abort();
barrier.destroy();
};
}
function createBarrier(options) {
const { waitTimeoutMillis, signal } = options;
const resolvers = /* @__PURE__ */ new Set();
function wait() {
if (signal.aborted || !(waitTimeoutMillis > 0)) {
return Promise.resolve();
}
return new Promise((resolve) => {
const timeoutHandle = setTimeout(done, waitTimeoutMillis);
function done() {
resolvers.delete(done);
clearTimeout(timeoutHandle);
resolve();
}
resolvers.add(done);
});
}
function release() {
const resolversToCall = new Set(resolvers);
resolvers.clear();
for (const resolver of resolversToCall) {
resolver();
}
}
signal.addEventListener("abort", release);
return {
wait,
release,
destroy: () => signal.removeEventListener("abort", release)
};
}
exports.createBarrier = createBarrier;
exports.startTaskPipeline = startTaskPipeline;
//# sourceMappingURL=TaskPipeline.cjs.js.map
;