todos-contra-el-fuego-web/imports/startup/server/calcUnionAsync.js
vjrj 3d52e2f709
All checks were successful
build-image / build (push) Successful in 11m55s
docs(subsUnion): note why legacy telegram subs are skipped, not errors
2026-07-30 06:58:09 +02:00

54 lines
2.3 KiB
JavaScript

import tcircle from '@turf/circle';
import tunion from '@turf/union';
import ttrunc from '@turf/truncate';
const truncOptions = { precision: 6, coordinates: 2 };
// How many polygons to process before yielding to the event loop once.
const YIELD_EVERY = 100;
const yieldToEventLoop = () => new Promise((resolve) => { setImmediate(resolve); });
/**
* Circle-union of subscriptions, equivalent to map-common-utils' calcUnion(typeCircle=true),
* but split into a `for` loop that yields to the event loop every YIELD_EVERY polygons.
* The vendored calcUnion runs the same turf.union chain fully synchronously, which for
* thousands of subscriptions blocks Meteor's single-threaded DDP/HTTP handling for minutes
* (see plan-modernizacion notes on the subsUnion hang). This keeps the exact same geometry
* output while letting other requests interleave between chunks.
*/
const calcUnionAsync = async (subs, decorated) => {
const unionGroup = [];
for (let i = 0; i < subs.length; i += 1) {
const osub = subs[i];
try {
if (osub.location && osub.location.lat && osub.location.lon && osub.distance) {
const dsub = decorated(osub);
unionGroup.push(tcircle(
[dsub.location.lon, dsub.location.lat],
dsub.distance,
{ units: 'kilometers', steps: 144 }
));
} else {
// Expected for old telegram subscriptions predating the distance field
// (e.g. distance: null) — logged, not an error, safe to skip.
console.info(`Wrong element to do union ${JSON.stringify(osub)}`);
}
} catch (e) {
console.error(e, `Wrong element trying to make union ${JSON.stringify(osub)}`);
}
// Deliberate: yield to the event loop periodically instead of blocking it.
// eslint-disable-next-line no-await-in-loop
if (i % YIELD_EVERY === 0) await yieldToEventLoop();
}
let unionTemp = unionGroup.length > 0 ? ttrunc(unionGroup[0], truncOptions) : null;
for (let i = 1; i < unionGroup.length; i += 1) {
unionTemp = ttrunc(tunion(unionTemp, unionGroup[i]), truncOptions);
// Deliberate: yield to the event loop periodically instead of blocking it.
// eslint-disable-next-line no-await-in-loop
if (i % YIELD_EVERY === 0) await yieldToEventLoop();
}
return unionTemp;
};
export default calcUnionAsync;