@bitrix24/b24jssdk
Version:
Bitrix24 REST API JavaScript SDK
136 lines (133 loc) • 3.85 kB
JavaScript
/**
* @package @bitrix24/b24jssdk
* @version 1.1.0
* @copyright (c) 2026 Bitrix24
* @license MIT
* @see https://github.com/bitrix24/b24jssdk
* @see https://bitrix24.github.io/b24jssdk/
*/
import { LoggerFactory } from '../../../logger/logger-factory.mjs';
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
class AdaptiveDelayer {
static {
__name(this, "AdaptiveDelayer");
}
#config;
#operatingLimiter;
#stats = {
adaptiveDelays: 0,
totalAdaptiveDelay: 0
};
_logger;
getTitle() {
return "adaptiveDelayer";
}
constructor(config, operatingLimiter) {
this._logger = LoggerFactory.createNullLogger();
this.#config = config;
this.#operatingLimiter = operatingLimiter;
}
// region Logger ////
setLogger(logger) {
this._logger = logger;
}
getLogger() {
return this._logger;
}
// endregion ////
async canProceed(_requestId, _method, _params) {
return true;
}
/**
* Returns an adaptive delay based on previous experience
*/
async waitIfNeeded(requestId, method, params) {
if (!this.#config.enabled) {
return 0;
}
const delay = this.#calculateDelay(requestId, method, params);
if (delay > 0) {
this.incrementAdaptiveDelays();
this.#stats.totalAdaptiveDelay += delay;
}
return delay;
}
/**
* Calculates adaptive delay based on previous experience
*/
#calculateDelay(requestId, method, params) {
if (method === "batch") {
return this.#calculateBatchDelay(requestId, params);
}
const stats = this.#operatingLimiter.getMethodStat(method);
if (typeof stats === "undefined") {
return 0;
}
const usagePercent = stats.operating / this.#operatingLimiter.limitMs * 100;
if (usagePercent > this.#config.thresholdPercent) {
let adaptiveDelay = 0;
const now = Date.now();
if (stats.operating_reset_at > now) {
adaptiveDelay += (stats.operating_reset_at - now) * this.#config.coefficient;
} else {
adaptiveDelay += 7e3;
}
const waitDelay = Number.parseInt(Math.min(adaptiveDelay, this.#config.maxDelay).toFixed(0));
this.#logStat(requestId, method, usagePercent, adaptiveDelay, waitDelay);
return waitDelay;
}
return 0;
}
/**
* For `batch`, applies adaptive delay based on previous experience from commands
*/
#calculateBatchDelay(requestId, params) {
let maxDelay = 0;
if (!params?.cmd || !Array.isArray(params.cmd)) {
return maxDelay;
}
const batchMethods = params.cmd.map((row) => row.split("?")[0]).filter(Boolean);
const batchMethodsUnique = [...new Set(batchMethods)];
for (const methodName of batchMethodsUnique) {
const delay = this.#calculateDelay(requestId, `batch::${methodName}`, {});
maxDelay = Math.max(maxDelay, delay);
}
return maxDelay;
}
async updateStats(_requestId, _method, _data) {
}
async reset() {
this.#stats = {
adaptiveDelays: 0,
totalAdaptiveDelay: 0
};
}
getStats() {
return {
...this.#stats,
adaptiveDelayAvg: this.#stats.adaptiveDelays > 0 ? this.#stats.totalAdaptiveDelay / this.#stats.adaptiveDelays : 0
};
}
async setConfig(config) {
this.#config = config;
}
incrementAdaptiveDelays() {
this.#stats.adaptiveDelays++;
}
// region Log ////
#logStat(requestId, method, percent, adaptiveDelay, waitDelay) {
this.getLogger().debug(`${this.getTitle()} state for method ${method}`, {
requestId,
method,
percent: Number.parseFloat(percent.toFixed(2)),
delays: {
calculated: adaptiveDelay,
actual: waitDelay
}
});
}
// endregion ////
}
export { AdaptiveDelayer };
//# sourceMappingURL=adaptive-delayer.mjs.map