54 lines
2.3 KiB
JavaScript
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;
|