diff options
Diffstat (limited to 'frontend-old/node_modules/@grpc/grpc-js/src/load-balancer-outlier-detection.ts')
| -rw-r--r-- | frontend-old/node_modules/@grpc/grpc-js/src/load-balancer-outlier-detection.ts | 882 |
1 files changed, 0 insertions, 882 deletions
diff --git a/frontend-old/node_modules/@grpc/grpc-js/src/load-balancer-outlier-detection.ts b/frontend-old/node_modules/@grpc/grpc-js/src/load-balancer-outlier-detection.ts deleted file mode 100644 index 3e4b46f..0000000 --- a/frontend-old/node_modules/@grpc/grpc-js/src/load-balancer-outlier-detection.ts +++ /dev/null @@ -1,882 +0,0 @@ -/* - * 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. - * - */ - -import { ChannelOptions } from './channel-options'; -import { ConnectivityState } from './connectivity-state'; -import { LogVerbosity, Status } from './constants'; -import { durationToMs, isDuration, msToDuration } from './duration'; -import { - ChannelControlHelper, - createChildChannelControlHelper, - registerLoadBalancerType, -} from './experimental'; -import { - getFirstUsableConfig, - LoadBalancer, - LoadBalancingConfig, - validateLoadBalancingConfig, -} from './load-balancer'; -import { ChildLoadBalancerHandler } from './load-balancer-child-handler'; -import { PickArgs, Picker, PickResult, PickResultType } from './picker'; -import { - SubchannelAddress, - subchannelAddressToString, -} from './subchannel-address'; -import { - BaseSubchannelWrapper, - ConnectivityStateListener, - SubchannelInterface, -} from './subchannel-interface'; -import * as logging from './logging'; - -const TRACER_NAME = 'outlier_detection'; - -function trace(text: string): void { - logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); -} - -const TYPE_NAME = 'outlier_detection'; - -const OUTLIER_DETECTION_ENABLED = - (process.env.GRPC_EXPERIMENTAL_ENABLE_OUTLIER_DETECTION ?? 'true') === 'true'; - -export interface SuccessRateEjectionConfig { - readonly stdev_factor: number; - readonly enforcement_percentage: number; - readonly minimum_hosts: number; - readonly request_volume: number; -} - -export interface FailurePercentageEjectionConfig { - readonly threshold: number; - readonly enforcement_percentage: number; - readonly minimum_hosts: number; - readonly request_volume: number; -} - -const defaultSuccessRateEjectionConfig: SuccessRateEjectionConfig = { - stdev_factor: 1900, - enforcement_percentage: 100, - minimum_hosts: 5, - request_volume: 100, -}; - -const defaultFailurePercentageEjectionConfig: FailurePercentageEjectionConfig = - { - threshold: 85, - enforcement_percentage: 100, - minimum_hosts: 5, - request_volume: 50, - }; - -type TypeofValues = - | 'object' - | 'boolean' - | 'function' - | 'number' - | 'string' - | 'undefined'; - -function validateFieldType( - obj: any, - fieldName: string, - expectedType: TypeofValues, - objectName?: string -) { - 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: any, - fieldName: string, - objectName?: string -) { - const fullFieldName = objectName ? `${objectName}.${fieldName}` : fieldName; - if (fieldName in obj) { - if (!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 <= 315_576_000_000 && - obj[fieldName].nanos >= 0 && - obj[fieldName].nanos <= 999_999_999 - ) - ) { - throw new Error( - `outlier detection config ${fullFieldName} parse error: values out of range for non-negative Duaration` - ); - } - } -} - -function validatePercentage(obj: any, fieldName: string, objectName?: string) { - 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)` - ); - } -} - -export class OutlierDetectionLoadBalancingConfig - implements LoadBalancingConfig -{ - private readonly intervalMs: number; - private readonly baseEjectionTimeMs: number; - private readonly maxEjectionTimeMs: number; - private readonly maxEjectionPercent: number; - private readonly successRateEjection: SuccessRateEjectionConfig | null; - private readonly failurePercentageEjection: FailurePercentageEjectionConfig | null; - - constructor( - intervalMs: number | null, - baseEjectionTimeMs: number | null, - maxEjectionTimeMs: number | null, - maxEjectionPercent: number | null, - successRateEjection: Partial<SuccessRateEjectionConfig> | null, - failurePercentageEjection: Partial<FailurePercentageEjectionConfig> | null, - private readonly childPolicy: LoadBalancingConfig[] - ) { - if ( - childPolicy.length > 0 && - childPolicy[0].getLoadBalancerName() === 'pick_first' - ) { - throw new Error( - 'outlier_detection LB policy cannot have a pick_first child policy' - ); - } - this.intervalMs = intervalMs ?? 10_000; - this.baseEjectionTimeMs = baseEjectionTimeMs ?? 30_000; - this.maxEjectionTimeMs = maxEjectionTimeMs ?? 300_000; - this.maxEjectionPercent = maxEjectionPercent ?? 10; - this.successRateEjection = successRateEjection - ? { ...defaultSuccessRateEjectionConfig, ...successRateEjection } - : null; - this.failurePercentageEjection = failurePercentageEjection - ? { - ...defaultFailurePercentageEjectionConfig, - ...failurePercentageEjection, - } - : null; - } - getLoadBalancerName(): string { - return TYPE_NAME; - } - toJsonObject(): object { - return { - interval: msToDuration(this.intervalMs), - base_ejection_time: msToDuration(this.baseEjectionTimeMs), - max_ejection_time: 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(): number { - return this.intervalMs; - } - getBaseEjectionTimeMs(): number { - return this.baseEjectionTimeMs; - } - getMaxEjectionTimeMs(): number { - return this.maxEjectionTimeMs; - } - getMaxEjectionPercent(): number { - return this.maxEjectionPercent; - } - getSuccessRateEjectionConfig(): SuccessRateEjectionConfig | null { - return this.successRateEjection; - } - getFailurePercentageEjectionConfig(): FailurePercentageEjectionConfig | null { - return this.failurePercentageEjection; - } - getChildPolicy(): LoadBalancingConfig[] { - return this.childPolicy; - } - - copyWithChildPolicy( - childPolicy: LoadBalancingConfig[] - ): OutlierDetectionLoadBalancingConfig { - return new OutlierDetectionLoadBalancingConfig( - this.intervalMs, - this.baseEjectionTimeMs, - this.maxEjectionTimeMs, - this.maxEjectionPercent, - this.successRateEjection, - this.failurePercentageEjection, - childPolicy - ); - } - - static createFromJson(obj: any): OutlierDetectionLoadBalancingConfig { - 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 ? durationToMs(obj.interval) : null, - obj.base_ejection_time ? durationToMs(obj.base_ejection_time) : null, - obj.max_ejection_time ? durationToMs(obj.max_ejection_time) : null, - obj.max_ejection_percent ?? null, - obj.success_rate_ejection, - obj.failure_percentage_ejection, - obj.child_policy.map(validateLoadBalancingConfig) - ); - } -} - -class OutlierDetectionSubchannelWrapper - extends BaseSubchannelWrapper - implements SubchannelInterface -{ - private childSubchannelState: ConnectivityState; - private stateListeners: ConnectivityStateListener[] = []; - private ejected = false; - private refCount = 0; - constructor( - childSubchannel: SubchannelInterface, - private mapEntry?: MapEntry - ) { - super(childSubchannel); - this.childSubchannelState = childSubchannel.getConnectivityState(); - childSubchannel.addConnectivityStateListener( - (subchannel, previousState, newState, keepaliveTime) => { - this.childSubchannelState = newState; - if (!this.ejected) { - for (const listener of this.stateListeners) { - listener(this, previousState, newState, keepaliveTime); - } - } - } - ); - } - - getConnectivityState(): ConnectivityState { - if (this.ejected) { - return 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: ConnectivityStateListener) { - this.stateListeners.push(listener); - } - - /** - * Remove a listener previously added with `addConnectivityStateListener` - * @param listener A reference to a function previously passed to - * `addConnectivityStateListener` - */ - removeConnectivityStateListener(listener: ConnectivityStateListener) { - 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, - ConnectivityState.TRANSIENT_FAILURE, - -1 - ); - } - } - - uneject() { - this.ejected = false; - for (const listener of this.stateListeners) { - listener( - this, - ConnectivityState.TRANSIENT_FAILURE, - this.childSubchannelState, - -1 - ); - } - } - - getMapEntry(): MapEntry | undefined { - return this.mapEntry; - } - - getWrappedSubchannel(): SubchannelInterface { - return this.child; - } -} - -interface CallCountBucket { - success: number; - failure: number; -} - -function createEmptyBucket(): CallCountBucket { - return { - success: 0, - failure: 0, - }; -} - -class CallCounter { - private activeBucket: CallCountBucket = createEmptyBucket(); - private inactiveBucket: CallCountBucket = 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; - } -} - -interface MapEntry { - counter: CallCounter; - currentEjectionTimestamp: Date | null; - ejectionTimeMultiplier: number; - subchannelWrappers: OutlierDetectionSubchannelWrapper[]; -} - -class OutlierDetectionPicker implements Picker { - constructor(private wrappedPicker: Picker, private countCalls: boolean) {} - pick(pickArgs: PickArgs): PickResult { - const wrappedPick = this.wrappedPicker.pick(pickArgs); - if (wrappedPick.pickResultType === PickResultType.COMPLETE) { - const subchannelWrapper = - wrappedPick.subchannel as OutlierDetectionSubchannelWrapper; - const mapEntry = subchannelWrapper.getMapEntry(); - if (mapEntry) { - let onCallEnded = wrappedPick.onCallEnded; - if (this.countCalls) { - onCallEnded = statusCode => { - if (statusCode === Status.OK) { - mapEntry.counter.addSuccess(); - } else { - mapEntry.counter.addFailure(); - } - wrappedPick.onCallEnded?.(statusCode); - }; - } - return { - ...wrappedPick, - subchannel: subchannelWrapper.getWrappedSubchannel(), - onCallEnded: onCallEnded, - }; - } else { - return { - ...wrappedPick, - subchannel: subchannelWrapper.getWrappedSubchannel(), - }; - } - } else { - return wrappedPick; - } - } -} - -export class OutlierDetectionLoadBalancer implements LoadBalancer { - private childBalancer: ChildLoadBalancerHandler; - private addressMap: Map<string, MapEntry> = new Map<string, MapEntry>(); - private latestConfig: OutlierDetectionLoadBalancingConfig | null = null; - private ejectionTimer: NodeJS.Timeout; - private timerStartTime: Date | null = null; - - constructor(channelControlHelper: ChannelControlHelper) { - this.childBalancer = new ChildLoadBalancerHandler( - createChildChannelControlHelper(channelControlHelper, { - createSubchannel: ( - subchannelAddress: SubchannelAddress, - subchannelArgs: ChannelOptions - ) => { - const originalSubchannel = channelControlHelper.createSubchannel( - subchannelAddress, - subchannelArgs - ); - const mapEntry = this.addressMap.get( - subchannelAddressToString(subchannelAddress) - ); - const subchannelWrapper = new OutlierDetectionSubchannelWrapper( - originalSubchannel, - mapEntry - ); - if (mapEntry?.currentEjectionTimestamp !== null) { - // If the address is ejected, propagate that to the new subchannel wrapper - subchannelWrapper.eject(); - } - mapEntry?.subchannelWrappers.push(subchannelWrapper); - return subchannelWrapper; - }, - updateState: (connectivityState: ConnectivityState, picker: Picker) => { - if (connectivityState === ConnectivityState.READY) { - channelControlHelper.updateState( - connectivityState, - new OutlierDetectionPicker(picker, this.isCountingEnabled()) - ); - } else { - channelControlHelper.updateState(connectivityState, picker); - } - }, - }) - ); - this.ejectionTimer = setInterval(() => {}, 0); - clearInterval(this.ejectionTimer); - } - - private isCountingEnabled(): boolean { - return ( - this.latestConfig !== null && - (this.latestConfig.getSuccessRateEjectionConfig() !== null || - this.latestConfig.getFailurePercentageEjectionConfig() !== null) - ); - } - - private getCurrentEjectionPercent() { - let ejectionCount = 0; - for (const mapEntry of this.addressMap.values()) { - if (mapEntry.currentEjectionTimestamp !== null) { - ejectionCount += 1; - } - } - return (ejectionCount * 100) / this.addressMap.size; - } - - private runSuccessRateCheck(ejectionTimestamp: Date) { - 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: number[] = []; - for (const [address, mapEntry] of this.addressMap) { - const successes = mapEntry.counter.getLastSuccesses(); - const failures = mapEntry.counter.getLastFailures(); - trace( - 'Stats for ' + - address + - ': successes=' + - successes + - ' failures=' + - failures + - ' targetRequestVolume=' + - targetRequestVolume - ); - 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); - } - } - } - } - - private runFailurePercentageCheck(ejectionTimestamp: Date) { - 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); - } - } - } - } - - private eject(mapEntry: MapEntry, ejectionTimestamp: Date) { - mapEntry.currentEjectionTimestamp = new Date(); - mapEntry.ejectionTimeMultiplier += 1; - for (const subchannelWrapper of mapEntry.subchannelWrappers) { - subchannelWrapper.eject(); - } - } - - private uneject(mapEntry: MapEntry) { - mapEntry.currentEjectionTimestamp = null; - for (const subchannelWrapper of mapEntry.subchannelWrappers) { - subchannelWrapper.uneject(); - } - } - - private switchAllBuckets() { - for (const mapEntry of this.addressMap.values()) { - mapEntry.counter.switchBuckets(); - } - } - - private startTimer(delayMs: number) { - this.ejectionTimer = setTimeout(() => this.runChecks(), delayMs); - this.ejectionTimer.unref?.(); - } - - private 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: SubchannelAddress[], - lbConfig: LoadBalancingConfig, - attributes: { [key: string]: unknown } - ): void { - if (!(lbConfig instanceof OutlierDetectionLoadBalancingConfig)) { - return; - } - const subchannelAddresses = new Set<string>(); - for (const address of addressList) { - subchannelAddresses.add(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: LoadBalancingConfig = 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(): void { - this.childBalancer.exitIdle(); - } - resetBackoff(): void { - this.childBalancer.resetBackoff(); - } - destroy(): void { - clearTimeout(this.ejectionTimer); - this.childBalancer.destroy(); - } - getTypeName(): string { - return TYPE_NAME; - } -} - -export function setup() { - if (OUTLIER_DETECTION_ENABLED) { - registerLoadBalancerType( - TYPE_NAME, - OutlierDetectionLoadBalancer, - OutlierDetectionLoadBalancingConfig - ); - } -} |
