UNPKG

tencentcloud-edgeone-migration-nodejs-v2

Version:

tencentcloud cdn config copy to edgeone

134 lines 5.12 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Ratelimit = void 0; const errors_1 = require("../errors"); const metadata_1 = require("../metadata"); const plugins_1 = require("../plugins"); const rules_1 = require("../rules"); const utils_1 = require("../utils"); const ratelimiter_1 = require("./ratelimiter"); const kDefaultOptions = { outdatedPeriod: 2, idlePeriod: 10, instanceUpdateTime: 5 * utils_1.kSeconds, updatePercent: 0.8 }; class Ratelimit { constructor(global, logger, registry, ratelimit, shaping, options) { this.global = global; this.logger = logger; this.registry = registry; this.ratelimit = ratelimit; this.shaping = shaping; this.limiters = new WeakMap(); this.disposed = false; this.options = Object.assign(Object.assign({}, kDefaultOptions), options); } dispose() { this.disposed = true; } async query(namespace, service, cluster = "", labels, id) { if (this.disposed) { throw new errors_1.StateError("Already disposed"); } const rules = await this.registry.fetch(plugins_1.RegistryCategory.Ratelimit, namespace, service); let selectedRule; if (typeof id === "string" && id !== "") { /** fast case */ selectedRule = rules.find(rule => rule.id === id); } if (typeof selectedRule === "undefined") { const { globalVariables } = this.global; // eslint-disable-next-line @typescript-eslint/prefer-for-of for (let i = 0; i < rules.length; i += 1) { /** slow case */ const rule = rules[i]; if (rule.cluster === cluster && (0, metadata_1.isMetadataMatch)(labels, rule.labels, globalVariables) && (selectedRule === undefined || rule.priority > selectedRule.priority)) { selectedRule = rule; } } } return selectedRule; } acquire(namespace, service, amount, rule) { const quotas = []; if (this.disposed) { const err = new errors_1.StateError("Already disposed"); for (let i = 0; i < amount; i += 1) { quotas.push(Promise.reject(err)); } return quotas; } /** * 当规则不存在时,默认放通所有配额 */ if (typeof rule === "undefined") { for (let i = 0; i < amount; i += 1) { quotas.push(Promise.resolve()); } return quotas; } let limiter; if (!this.limiters.has(rule)) { switch (rule.type) { case rules_1.LimitType.Local: { limiter = new ratelimiter_1.LocalRatelimiter(rule, this.options); break; } case rules_1.LimitType.Global: { limiter = new ratelimiter_1.GlobalRatelimiter(namespace, service, rule, this.logger, this.registry, this.ratelimit, this.options); break; } default: { (0, utils_1.UNREACHABLE)(); } } this.limiters.set(rule, limiter); } let shaping; if (rule.action !== "") { shaping = this.shaping.find(plugin => plugin.name === rule.action); if (typeof shaping === "undefined") { throw new errors_1.PluginError(`action(${rule.action}) implement not found`); } } for (let i = 0; i < amount; i += 1) { let quota = Promise.resolve(); if (rule.enable) { if (typeof shaping !== "undefined") { quota = quota .then(() => limiter.getPartition()) .then(partition => shaping.inFlow(rule, partition)); } quota = quota .then(() => this.allocation(rule)) .then(result => this.produce(rule, result)); } quotas.push(quota); } return quotas; } allocation(rule) { const limiter = this.limiters.get(rule); if (typeof limiter === "undefined") { throw new errors_1.StateError("current rate limit rule has been changed, all allocations are rejected"); } return limiter.consume(); } produce(rule, result) { if (!result) { throw new errors_1.StateError("no available quota"); } if (rule.resource === rules_1.LimitResource.Concurrency) { return () => { const limiter = this.limiters.get(rule); if (typeof limiter === "undefined") { throw new errors_1.StateError("current rate limit rule has been changed, all releases are rejected"); } return limiter.return(); }; } } } exports.Ratelimit = Ratelimit; //# sourceMappingURL=ratelimit.js.map