UNPKG

@grammyjs/runner

Version:

Scale grammY bots that use long polling

97 lines (96 loc) 3.58 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createSource = void 0; const STAT_LEN = 16; /** * Creates an update source based on the given update supplier. * * @param supplier An update supplier to use for requesting updates * @returns An update source */ function createSource(supplier, options = {}) { const { speedTrafficBalance = 0.0, maxDelayMilliseconds = 500 } = options; let active = false; let endWait = () => { }; let waitHandle = undefined; let controller; function deactivate() { active = false; clearTimeout(waitHandle); waitHandle = undefined; endWait(); } let updateGenerator = worker(); let pace = Infinity; const bounded = Math.max(0.0, Math.min(speedTrafficBalance, 1.0)); // [0;1] const balance = 100 * bounded / Math.max(1, maxDelayMilliseconds); // number of wanted updates per call // We take two cyclic buffers to store update counts and durations // for the last STAT_LEN update calls. const counts = Array(STAT_LEN).fill(100); const durations = Array(STAT_LEN).fill(1); // We also keep track of the sum of the values in each buffer let totalCounts = 100 * STAT_LEN; // sum of counts let totalDuration = 1 * STAT_LEN; // sum of durations // Write index for both buffers let index = 0; /** Records a pair ms/items and estimates the pause length */ const record = balance === 0 ? () => 0 // do not perform any tracking if the balance is 0.0 : (newCount, newDuration) => { // save old const oldCount = counts[index]; const oldDuration = durations[index]; // write to buffer counts[index] = newCount; durations[index] = newDuration; // update sums totalCounts += newCount - oldCount; totalDuration += newDuration - oldDuration; // move index index = (index + 1) % STAT_LEN; // estimate time to wait, and cap it smoothly at maxDelay const estimate = balance * totalDuration / (totalCounts || 1); const capped = maxDelayMilliseconds * Math.tanh(estimate); return capped; }; async function* worker() { active = true; do { controller = new node_shim_js_1.AbortController(); controller.signal.addEventListener("abort", deactivate); try { const pre = Date.now(); const items = await supplier.supply(pace, controller.signal); const post = Date.now(); yield items; const wait = record(items.length, post - pre); if (items.length < 100 && wait > 0) { await new Promise((r) => { endWait = r; waitHandle = setTimeout(r, wait); }); } } catch (e) { if (!controller.signal.aborted) throw e; close(); break; } } while (active); } function close() { deactivate(); controller.abort(); updateGenerator = worker(); pace = Infinity; } return { generator: () => updateGenerator, setGeneratorPace: (newPace) => pace = newPace, isActive: () => active, close: () => close(), }; } exports.createSource = createSource; const node_shim_js_1 = require("./node-shim.js");