123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579 |
- "use strict";
- /*
- * Copyright 2022 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
- var _a;
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.setup = exports.OutlierDetectionLoadBalancer = exports.OutlierDetectionLoadBalancingConfig = void 0;
- const connectivity_state_1 = require("./connectivity-state");
- const constants_1 = require("./constants");
- const duration_1 = require("./duration");
- const experimental_1 = require("./experimental");
- const filter_1 = require("./filter");
- const load_balancer_1 = require("./load-balancer");
- const load_balancer_child_handler_1 = require("./load-balancer-child-handler");
- const picker_1 = require("./picker");
- const subchannel_address_1 = require("./subchannel-address");
- const subchannel_interface_1 = require("./subchannel-interface");
- const logging = require("./logging");
- const TRACER_NAME = 'outlier_detection';
- function trace(text) {
- logging.trace(constants_1.LogVerbosity.DEBUG, TRACER_NAME, text);
- }
- const TYPE_NAME = 'outlier_detection';
- const OUTLIER_DETECTION_ENABLED = ((_a = process.env.GRPC_EXPERIMENTAL_ENABLE_OUTLIER_DETECTION) !== null && _a !== void 0 ? _a : 'true') === 'true';
- const defaultSuccessRateEjectionConfig = {
- stdev_factor: 1900,
- enforcement_percentage: 100,
- minimum_hosts: 5,
- request_volume: 100
- };
- const defaultFailurePercentageEjectionConfig = {
- threshold: 85,
- enforcement_percentage: 100,
- minimum_hosts: 5,
- request_volume: 50
- };
- function validateFieldType(obj, fieldName, expectedType, objectName) {
- if (fieldName in obj && typeof obj[fieldName] !== expectedType) {
- const fullFieldName = objectName ? `${objectName}.${fieldName}` : fieldName;
- throw new Error(`outlier detection config ${fullFieldName} parse error: expected ${expectedType}, got ${typeof obj[fieldName]}`);
- }
- }
- function validatePositiveDuration(obj, fieldName, objectName) {
- const fullFieldName = objectName ? `${objectName}.${fieldName}` : fieldName;
- if (fieldName in obj) {
- if (!duration_1.isDuration(obj[fieldName])) {
- throw new Error(`outlier detection config ${fullFieldName} parse error: expected Duration, got ${typeof obj[fieldName]}`);
- }
- if (!(obj[fieldName].seconds >= 0 && obj[fieldName].seconds <= 315576000000 && obj[fieldName].nanos >= 0 && obj[fieldName].nanos <= 999999999)) {
- throw new Error(`outlier detection config ${fullFieldName} parse error: values out of range for non-negative Duaration`);
- }
- }
- }
- function validatePercentage(obj, fieldName, objectName) {
- const fullFieldName = objectName ? `${objectName}.${fieldName}` : fieldName;
- validateFieldType(obj, fieldName, 'number', objectName);
- if (fieldName in obj && !(obj[fieldName] >= 0 && obj[fieldName] <= 100)) {
- throw new Error(`outlier detection config ${fullFieldName} parse error: value out of range for percentage (0-100)`);
- }
- }
- class OutlierDetectionLoadBalancingConfig {
- constructor(intervalMs, baseEjectionTimeMs, maxEjectionTimeMs, maxEjectionPercent, successRateEjection, failurePercentageEjection, childPolicy) {
- this.childPolicy = childPolicy;
- this.intervalMs = intervalMs !== null && intervalMs !== void 0 ? intervalMs : 10000;
- this.baseEjectionTimeMs = baseEjectionTimeMs !== null && baseEjectionTimeMs !== void 0 ? baseEjectionTimeMs : 30000;
- this.maxEjectionTimeMs = maxEjectionTimeMs !== null && maxEjectionTimeMs !== void 0 ? maxEjectionTimeMs : 300000;
- this.maxEjectionPercent = maxEjectionPercent !== null && maxEjectionPercent !== void 0 ? maxEjectionPercent : 10;
- this.successRateEjection = successRateEjection ? Object.assign(Object.assign({}, defaultSuccessRateEjectionConfig), successRateEjection) : null;
- this.failurePercentageEjection = failurePercentageEjection ? Object.assign(Object.assign({}, defaultFailurePercentageEjectionConfig), failurePercentageEjection) : null;
- }
- getLoadBalancerName() {
- return TYPE_NAME;
- }
- toJsonObject() {
- return {
- interval: duration_1.msToDuration(this.intervalMs),
- base_ejection_time: duration_1.msToDuration(this.baseEjectionTimeMs),
- max_ejection_time: duration_1.msToDuration(this.maxEjectionTimeMs),
- max_ejection_percent: this.maxEjectionPercent,
- success_rate_ejection: this.successRateEjection,
- failure_percentage_ejection: this.failurePercentageEjection,
- child_policy: this.childPolicy.map(policy => policy.toJsonObject())
- };
- }
- getIntervalMs() {
- return this.intervalMs;
- }
- getBaseEjectionTimeMs() {
- return this.baseEjectionTimeMs;
- }
- getMaxEjectionTimeMs() {
- return this.maxEjectionTimeMs;
- }
- getMaxEjectionPercent() {
- return this.maxEjectionPercent;
- }
- getSuccessRateEjectionConfig() {
- return this.successRateEjection;
- }
- getFailurePercentageEjectionConfig() {
- return this.failurePercentageEjection;
- }
- getChildPolicy() {
- return this.childPolicy;
- }
- copyWithChildPolicy(childPolicy) {
- return new OutlierDetectionLoadBalancingConfig(this.intervalMs, this.baseEjectionTimeMs, this.maxEjectionTimeMs, this.maxEjectionPercent, this.successRateEjection, this.failurePercentageEjection, childPolicy);
- }
- static createFromJson(obj) {
- var _a;
- validatePositiveDuration(obj, 'interval');
- validatePositiveDuration(obj, 'base_ejection_time');
- validatePositiveDuration(obj, 'max_ejection_time');
- validatePercentage(obj, 'max_ejection_percent');
- if ('success_rate_ejection' in obj) {
- if (typeof obj.success_rate_ejection !== 'object') {
- throw new Error('outlier detection config success_rate_ejection must be an object');
- }
- validateFieldType(obj.success_rate_ejection, 'stdev_factor', 'number', 'success_rate_ejection');
- validatePercentage(obj.success_rate_ejection, 'enforcement_percentage', 'success_rate_ejection');
- validateFieldType(obj.success_rate_ejection, 'minimum_hosts', 'number', 'success_rate_ejection');
- validateFieldType(obj.success_rate_ejection, 'request_volume', 'number', 'success_rate_ejection');
- }
- if ('failure_percentage_ejection' in obj) {
- if (typeof obj.failure_percentage_ejection !== 'object') {
- throw new Error('outlier detection config failure_percentage_ejection must be an object');
- }
- validatePercentage(obj.failure_percentage_ejection, 'threshold', 'failure_percentage_ejection');
- validatePercentage(obj.failure_percentage_ejection, 'enforcement_percentage', 'failure_percentage_ejection');
- validateFieldType(obj.failure_percentage_ejection, 'minimum_hosts', 'number', 'failure_percentage_ejection');
- validateFieldType(obj.failure_percentage_ejection, 'request_volume', 'number', 'failure_percentage_ejection');
- }
- return new OutlierDetectionLoadBalancingConfig(obj.interval ? duration_1.durationToMs(obj.interval) : null, obj.base_ejection_time ? duration_1.durationToMs(obj.base_ejection_time) : null, obj.max_ejection_time ? duration_1.durationToMs(obj.max_ejection_time) : null, (_a = obj.max_ejection_percent) !== null && _a !== void 0 ? _a : null, obj.success_rate_ejection, obj.failure_percentage_ejection, obj.child_policy.map(load_balancer_1.validateLoadBalancingConfig));
- }
- }
- exports.OutlierDetectionLoadBalancingConfig = OutlierDetectionLoadBalancingConfig;
- class OutlierDetectionSubchannelWrapper extends subchannel_interface_1.BaseSubchannelWrapper {
- constructor(childSubchannel, mapEntry) {
- super(childSubchannel);
- this.mapEntry = mapEntry;
- this.stateListeners = [];
- this.ejected = false;
- this.refCount = 0;
- this.childSubchannelState = childSubchannel.getConnectivityState();
- childSubchannel.addConnectivityStateListener((subchannel, previousState, newState) => {
- this.childSubchannelState = newState;
- if (!this.ejected) {
- for (const listener of this.stateListeners) {
- listener(this, previousState, newState);
- }
- }
- });
- }
- getConnectivityState() {
- if (this.ejected) {
- return connectivity_state_1.ConnectivityState.TRANSIENT_FAILURE;
- }
- else {
- return this.childSubchannelState;
- }
- }
- /**
- * Add a listener function to be called whenever the wrapper's
- * connectivity state changes.
- * @param listener
- */
- addConnectivityStateListener(listener) {
- this.stateListeners.push(listener);
- }
- /**
- * Remove a listener previously added with `addConnectivityStateListener`
- * @param listener A reference to a function previously passed to
- * `addConnectivityStateListener`
- */
- removeConnectivityStateListener(listener) {
- const listenerIndex = this.stateListeners.indexOf(listener);
- if (listenerIndex > -1) {
- this.stateListeners.splice(listenerIndex, 1);
- }
- }
- ref() {
- this.child.ref();
- this.refCount += 1;
- }
- unref() {
- this.child.unref();
- this.refCount -= 1;
- if (this.refCount <= 0) {
- if (this.mapEntry) {
- const index = this.mapEntry.subchannelWrappers.indexOf(this);
- if (index >= 0) {
- this.mapEntry.subchannelWrappers.splice(index, 1);
- }
- }
- }
- }
- eject() {
- this.ejected = true;
- for (const listener of this.stateListeners) {
- listener(this, this.childSubchannelState, connectivity_state_1.ConnectivityState.TRANSIENT_FAILURE);
- }
- }
- uneject() {
- this.ejected = false;
- for (const listener of this.stateListeners) {
- listener(this, connectivity_state_1.ConnectivityState.TRANSIENT_FAILURE, this.childSubchannelState);
- }
- }
- getMapEntry() {
- return this.mapEntry;
- }
- getWrappedSubchannel() {
- return this.child;
- }
- }
- function createEmptyBucket() {
- return {
- success: 0,
- failure: 0
- };
- }
- class CallCounter {
- constructor() {
- this.activeBucket = createEmptyBucket();
- this.inactiveBucket = createEmptyBucket();
- }
- addSuccess() {
- this.activeBucket.success += 1;
- }
- addFailure() {
- this.activeBucket.failure += 1;
- }
- switchBuckets() {
- this.inactiveBucket = this.activeBucket;
- this.activeBucket = createEmptyBucket();
- }
- getLastSuccesses() {
- return this.inactiveBucket.success;
- }
- getLastFailures() {
- return this.inactiveBucket.failure;
- }
- }
- class OutlierDetectionCounterFilter extends filter_1.BaseFilter {
- constructor(callCounter) {
- super();
- this.callCounter = callCounter;
- }
- receiveTrailers(status) {
- if (status.code === constants_1.Status.OK) {
- this.callCounter.addSuccess();
- }
- else {
- this.callCounter.addFailure();
- }
- return status;
- }
- }
- class OutlierDetectionCounterFilterFactory {
- constructor(callCounter) {
- this.callCounter = callCounter;
- }
- createFilter(callStream) {
- return new OutlierDetectionCounterFilter(this.callCounter);
- }
- }
- class OutlierDetectionPicker {
- constructor(wrappedPicker, countCalls) {
- this.wrappedPicker = wrappedPicker;
- this.countCalls = countCalls;
- }
- pick(pickArgs) {
- const wrappedPick = this.wrappedPicker.pick(pickArgs);
- if (wrappedPick.pickResultType === picker_1.PickResultType.COMPLETE) {
- const subchannelWrapper = wrappedPick.subchannel;
- const mapEntry = subchannelWrapper.getMapEntry();
- if (mapEntry) {
- const extraFilterFactories = [...wrappedPick.extraFilterFactories];
- if (this.countCalls) {
- extraFilterFactories.push(new OutlierDetectionCounterFilterFactory(mapEntry.counter));
- }
- return Object.assign(Object.assign({}, wrappedPick), { subchannel: subchannelWrapper.getWrappedSubchannel(), extraFilterFactories: extraFilterFactories });
- }
- else {
- return Object.assign(Object.assign({}, wrappedPick), { subchannel: subchannelWrapper.getWrappedSubchannel() });
- }
- }
- else {
- return wrappedPick;
- }
- }
- }
- class OutlierDetectionLoadBalancer {
- constructor(channelControlHelper) {
- this.addressMap = new Map();
- this.latestConfig = null;
- this.timerStartTime = null;
- this.childBalancer = new load_balancer_child_handler_1.ChildLoadBalancerHandler(experimental_1.createChildChannelControlHelper(channelControlHelper, {
- createSubchannel: (subchannelAddress, subchannelArgs) => {
- const originalSubchannel = channelControlHelper.createSubchannel(subchannelAddress, subchannelArgs);
- const mapEntry = this.addressMap.get(subchannel_address_1.subchannelAddressToString(subchannelAddress));
- const subchannelWrapper = new OutlierDetectionSubchannelWrapper(originalSubchannel, mapEntry);
- if ((mapEntry === null || mapEntry === void 0 ? void 0 : mapEntry.currentEjectionTimestamp) !== null) {
- // If the address is ejected, propagate that to the new subchannel wrapper
- subchannelWrapper.eject();
- }
- mapEntry === null || mapEntry === void 0 ? void 0 : mapEntry.subchannelWrappers.push(subchannelWrapper);
- return subchannelWrapper;
- },
- updateState: (connectivityState, picker) => {
- if (connectivityState === connectivity_state_1.ConnectivityState.READY) {
- channelControlHelper.updateState(connectivityState, new OutlierDetectionPicker(picker, this.isCountingEnabled()));
- }
- else {
- channelControlHelper.updateState(connectivityState, picker);
- }
- }
- }));
- this.ejectionTimer = setInterval(() => { }, 0);
- clearInterval(this.ejectionTimer);
- }
- isCountingEnabled() {
- return this.latestConfig !== null &&
- (this.latestConfig.getSuccessRateEjectionConfig() !== null ||
- this.latestConfig.getFailurePercentageEjectionConfig() !== null);
- }
- getCurrentEjectionPercent() {
- let ejectionCount = 0;
- for (const mapEntry of this.addressMap.values()) {
- if (mapEntry.currentEjectionTimestamp !== null) {
- ejectionCount += 1;
- }
- }
- return (ejectionCount * 100) / this.addressMap.size;
- }
- runSuccessRateCheck(ejectionTimestamp) {
- if (!this.latestConfig) {
- return;
- }
- const successRateConfig = this.latestConfig.getSuccessRateEjectionConfig();
- if (!successRateConfig) {
- return;
- }
- trace('Running success rate check');
- // Step 1
- const targetRequestVolume = successRateConfig.request_volume;
- let addresesWithTargetVolume = 0;
- const successRates = [];
- for (const mapEntry of this.addressMap.values()) {
- const successes = mapEntry.counter.getLastSuccesses();
- const failures = mapEntry.counter.getLastFailures();
- if (successes + failures >= targetRequestVolume) {
- addresesWithTargetVolume += 1;
- successRates.push(successes / (successes + failures));
- }
- }
- trace('Found ' + addresesWithTargetVolume + ' success rate candidates; currentEjectionPercent=' + this.getCurrentEjectionPercent() + ' successRates=[' + successRates + ']');
- if (addresesWithTargetVolume < successRateConfig.minimum_hosts) {
- return;
- }
- // Step 2
- const successRateMean = successRates.reduce((a, b) => a + b) / successRates.length;
- let successRateDeviationSum = 0;
- for (const rate of successRates) {
- const deviation = rate - successRateMean;
- successRateDeviationSum += deviation * deviation;
- }
- const successRateVariance = successRateDeviationSum / successRates.length;
- const successRateStdev = Math.sqrt(successRateVariance);
- const ejectionThreshold = successRateMean - successRateStdev * (successRateConfig.stdev_factor / 1000);
- trace('stdev=' + successRateStdev + ' ejectionThreshold=' + ejectionThreshold);
- // Step 3
- for (const [address, mapEntry] of this.addressMap.entries()) {
- // Step 3.i
- if (this.getCurrentEjectionPercent() >= this.latestConfig.getMaxEjectionPercent()) {
- break;
- }
- // Step 3.ii
- const successes = mapEntry.counter.getLastSuccesses();
- const failures = mapEntry.counter.getLastFailures();
- if (successes + failures < targetRequestVolume) {
- continue;
- }
- // Step 3.iii
- const successRate = successes / (successes + failures);
- trace('Checking candidate ' + address + ' successRate=' + successRate);
- if (successRate < ejectionThreshold) {
- const randomNumber = Math.random() * 100;
- trace('Candidate ' + address + ' randomNumber=' + randomNumber + ' enforcement_percentage=' + successRateConfig.enforcement_percentage);
- if (randomNumber < successRateConfig.enforcement_percentage) {
- trace('Ejecting candidate ' + address);
- this.eject(mapEntry, ejectionTimestamp);
- }
- }
- }
- }
- runFailurePercentageCheck(ejectionTimestamp) {
- if (!this.latestConfig) {
- return;
- }
- const failurePercentageConfig = this.latestConfig.getFailurePercentageEjectionConfig();
- if (!failurePercentageConfig) {
- return;
- }
- trace('Running failure percentage check. threshold=' + failurePercentageConfig.threshold + ' request volume threshold=' + failurePercentageConfig.request_volume);
- // Step 1
- let addressesWithTargetVolume = 0;
- for (const mapEntry of this.addressMap.values()) {
- const successes = mapEntry.counter.getLastSuccesses();
- const failures = mapEntry.counter.getLastFailures();
- if (successes + failures >= failurePercentageConfig.request_volume) {
- addressesWithTargetVolume += 1;
- }
- }
- if (addressesWithTargetVolume < failurePercentageConfig.minimum_hosts) {
- return;
- }
- // Step 2
- for (const [address, mapEntry] of this.addressMap.entries()) {
- // Step 2.i
- if (this.getCurrentEjectionPercent() >= this.latestConfig.getMaxEjectionPercent()) {
- break;
- }
- // Step 2.ii
- const successes = mapEntry.counter.getLastSuccesses();
- const failures = mapEntry.counter.getLastFailures();
- trace('Candidate successes=' + successes + ' failures=' + failures);
- if (successes + failures < failurePercentageConfig.request_volume) {
- continue;
- }
- // Step 2.iii
- const failurePercentage = (failures * 100) / (failures + successes);
- if (failurePercentage > failurePercentageConfig.threshold) {
- const randomNumber = Math.random() * 100;
- trace('Candidate ' + address + ' randomNumber=' + randomNumber + ' enforcement_percentage=' + failurePercentageConfig.enforcement_percentage);
- if (randomNumber < failurePercentageConfig.enforcement_percentage) {
- trace('Ejecting candidate ' + address);
- this.eject(mapEntry, ejectionTimestamp);
- }
- }
- }
- }
- eject(mapEntry, ejectionTimestamp) {
- mapEntry.currentEjectionTimestamp = new Date();
- mapEntry.ejectionTimeMultiplier += 1;
- for (const subchannelWrapper of mapEntry.subchannelWrappers) {
- subchannelWrapper.eject();
- }
- }
- uneject(mapEntry) {
- mapEntry.currentEjectionTimestamp = null;
- for (const subchannelWrapper of mapEntry.subchannelWrappers) {
- subchannelWrapper.uneject();
- }
- }
- switchAllBuckets() {
- for (const mapEntry of this.addressMap.values()) {
- mapEntry.counter.switchBuckets();
- }
- }
- startTimer(delayMs) {
- this.ejectionTimer = setTimeout(() => this.runChecks(), delayMs);
- }
- runChecks() {
- const ejectionTimestamp = new Date();
- trace('Ejection timer running');
- this.switchAllBuckets();
- if (!this.latestConfig) {
- return;
- }
- this.timerStartTime = ejectionTimestamp;
- this.startTimer(this.latestConfig.getIntervalMs());
- this.runSuccessRateCheck(ejectionTimestamp);
- this.runFailurePercentageCheck(ejectionTimestamp);
- for (const [address, mapEntry] of this.addressMap.entries()) {
- if (mapEntry.currentEjectionTimestamp === null) {
- if (mapEntry.ejectionTimeMultiplier > 0) {
- mapEntry.ejectionTimeMultiplier -= 1;
- }
- }
- else {
- const baseEjectionTimeMs = this.latestConfig.getBaseEjectionTimeMs();
- const maxEjectionTimeMs = this.latestConfig.getMaxEjectionTimeMs();
- const returnTime = new Date(mapEntry.currentEjectionTimestamp.getTime());
- returnTime.setMilliseconds(returnTime.getMilliseconds() + Math.min(baseEjectionTimeMs * mapEntry.ejectionTimeMultiplier, Math.max(baseEjectionTimeMs, maxEjectionTimeMs)));
- if (returnTime < new Date()) {
- trace('Unejecting ' + address);
- this.uneject(mapEntry);
- }
- }
- }
- }
- updateAddressList(addressList, lbConfig, attributes) {
- if (!(lbConfig instanceof OutlierDetectionLoadBalancingConfig)) {
- return;
- }
- const subchannelAddresses = new Set();
- for (const address of addressList) {
- subchannelAddresses.add(subchannel_address_1.subchannelAddressToString(address));
- }
- for (const address of subchannelAddresses) {
- if (!this.addressMap.has(address)) {
- trace('Adding map entry for ' + address);
- this.addressMap.set(address, {
- counter: new CallCounter(),
- currentEjectionTimestamp: null,
- ejectionTimeMultiplier: 0,
- subchannelWrappers: []
- });
- }
- }
- for (const key of this.addressMap.keys()) {
- if (!subchannelAddresses.has(key)) {
- trace('Removing map entry for ' + key);
- this.addressMap.delete(key);
- }
- }
- const childPolicy = load_balancer_1.getFirstUsableConfig(lbConfig.getChildPolicy(), true);
- this.childBalancer.updateAddressList(addressList, childPolicy, attributes);
- if (lbConfig.getSuccessRateEjectionConfig() || lbConfig.getFailurePercentageEjectionConfig()) {
- if (this.timerStartTime) {
- trace('Previous timer existed. Replacing timer');
- clearTimeout(this.ejectionTimer);
- const remainingDelay = lbConfig.getIntervalMs() - ((new Date()).getTime() - this.timerStartTime.getTime());
- this.startTimer(remainingDelay);
- }
- else {
- trace('Starting new timer');
- this.timerStartTime = new Date();
- this.startTimer(lbConfig.getIntervalMs());
- this.switchAllBuckets();
- }
- }
- else {
- trace('Counting disabled. Cancelling timer.');
- this.timerStartTime = null;
- clearTimeout(this.ejectionTimer);
- for (const mapEntry of this.addressMap.values()) {
- this.uneject(mapEntry);
- mapEntry.ejectionTimeMultiplier = 0;
- }
- }
- this.latestConfig = lbConfig;
- }
- exitIdle() {
- this.childBalancer.exitIdle();
- }
- resetBackoff() {
- this.childBalancer.resetBackoff();
- }
- destroy() {
- clearTimeout(this.ejectionTimer);
- this.childBalancer.destroy();
- }
- getTypeName() {
- return TYPE_NAME;
- }
- }
- exports.OutlierDetectionLoadBalancer = OutlierDetectionLoadBalancer;
- function setup() {
- if (OUTLIER_DETECTION_ENABLED) {
- experimental_1.registerLoadBalancerType(TYPE_NAME, OutlierDetectionLoadBalancer, OutlierDetectionLoadBalancingConfig);
- }
- }
- exports.setup = setup;
- //# sourceMappingURL=load-balancer-outlier-detection.js.map
|