mirror of https://github.com/grpc/grpc-node.git
grpc-js: Update outlier detection to address recent spec changes
This commit is contained in:
parent
879d13b6c3
commit
b07ea8b354
|
|
@ -334,17 +334,21 @@ class OutlierDetectionCounterFilterFactory implements FilterFactory<OutlierDetec
|
||||||
}
|
}
|
||||||
|
|
||||||
class OutlierDetectionPicker implements Picker {
|
class OutlierDetectionPicker implements Picker {
|
||||||
constructor(private wrappedPicker: Picker) {}
|
constructor(private wrappedPicker: Picker, private countCalls: boolean) {}
|
||||||
pick(pickArgs: PickArgs): PickResult {
|
pick(pickArgs: PickArgs): PickResult {
|
||||||
const wrappedPick = this.wrappedPicker.pick(pickArgs);
|
const wrappedPick = this.wrappedPicker.pick(pickArgs);
|
||||||
if (wrappedPick.pickResultType === PickResultType.COMPLETE) {
|
if (wrappedPick.pickResultType === PickResultType.COMPLETE) {
|
||||||
const subchannelWrapper = wrappedPick.subchannel as OutlierDetectionSubchannelWrapper;
|
const subchannelWrapper = wrappedPick.subchannel as OutlierDetectionSubchannelWrapper;
|
||||||
const mapEntry = subchannelWrapper.getMapEntry();
|
const mapEntry = subchannelWrapper.getMapEntry();
|
||||||
if (mapEntry) {
|
if (mapEntry) {
|
||||||
|
const extraFilterFactories = [...wrappedPick.extraFilterFactories];
|
||||||
|
if (this.countCalls) {
|
||||||
|
extraFilterFactories.push(new OutlierDetectionCounterFilterFactory(mapEntry.counter));
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
...wrappedPick,
|
...wrappedPick,
|
||||||
subchannel: subchannelWrapper.getWrappedSubchannel(),
|
subchannel: subchannelWrapper.getWrappedSubchannel(),
|
||||||
extraFilterFactories: [...wrappedPick.extraFilterFactories, new OutlierDetectionCounterFilterFactory(mapEntry.counter)]
|
extraFilterFactories: extraFilterFactories
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return wrappedPick;
|
return wrappedPick;
|
||||||
|
|
@ -361,6 +365,7 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer {
|
||||||
private addressMap: Map<string, MapEntry> = new Map<string, MapEntry>();
|
private addressMap: Map<string, MapEntry> = new Map<string, MapEntry>();
|
||||||
private latestConfig: OutlierDetectionLoadBalancingConfig | null = null;
|
private latestConfig: OutlierDetectionLoadBalancingConfig | null = null;
|
||||||
private ejectionTimer: NodeJS.Timer;
|
private ejectionTimer: NodeJS.Timer;
|
||||||
|
private timerStartTime: Date | null = null;
|
||||||
|
|
||||||
constructor(channelControlHelper: ChannelControlHelper) {
|
constructor(channelControlHelper: ChannelControlHelper) {
|
||||||
this.childBalancer = new ChildLoadBalancerHandler(createChildChannelControlHelper(channelControlHelper, {
|
this.childBalancer = new ChildLoadBalancerHandler(createChildChannelControlHelper(channelControlHelper, {
|
||||||
|
|
@ -373,7 +378,7 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer {
|
||||||
},
|
},
|
||||||
updateState: (connectivityState: ConnectivityState, picker: Picker) => {
|
updateState: (connectivityState: ConnectivityState, picker: Picker) => {
|
||||||
if (connectivityState === ConnectivityState.READY) {
|
if (connectivityState === ConnectivityState.READY) {
|
||||||
channelControlHelper.updateState(connectivityState, new OutlierDetectionPicker(picker));
|
channelControlHelper.updateState(connectivityState, new OutlierDetectionPicker(picker, this.isCountingEnabled()));
|
||||||
} else {
|
} else {
|
||||||
channelControlHelper.updateState(connectivityState, picker);
|
channelControlHelper.updateState(connectivityState, picker);
|
||||||
}
|
}
|
||||||
|
|
@ -383,6 +388,12 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer {
|
||||||
clearInterval(this.ejectionTimer);
|
clearInterval(this.ejectionTimer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private isCountingEnabled(): boolean {
|
||||||
|
return this.latestConfig !== null &&
|
||||||
|
(this.latestConfig.getSuccessRateEjectionConfig() !== null ||
|
||||||
|
this.latestConfig.getFailurePercentageEjectionConfig() !== null);
|
||||||
|
}
|
||||||
|
|
||||||
private getCurrentEjectionPercent() {
|
private getCurrentEjectionPercent() {
|
||||||
let ejectionCount = 0;
|
let ejectionCount = 0;
|
||||||
for (const mapEntry of this.addressMap.values()) {
|
for (const mapEntry of this.addressMap.values()) {
|
||||||
|
|
@ -501,16 +512,26 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private runChecks() {
|
private switchAllBuckets() {
|
||||||
const ejectionTimestamp = new Date();
|
|
||||||
|
|
||||||
for (const mapEntry of this.addressMap.values()) {
|
for (const mapEntry of this.addressMap.values()) {
|
||||||
mapEntry.counter.switchBuckets();
|
mapEntry.counter.switchBuckets();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private startTimer(delayMs: number) {
|
||||||
|
this.ejectionTimer = setTimeout(() => this.runChecks(), delayMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private runChecks() {
|
||||||
|
const ejectionTimestamp = new Date();
|
||||||
|
|
||||||
|
this.switchAllBuckets();
|
||||||
|
|
||||||
if (!this.latestConfig) {
|
if (!this.latestConfig) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this.timerStartTime = ejectionTimestamp;
|
||||||
|
this.startTimer(this.latestConfig.getIntervalMs());
|
||||||
|
|
||||||
this.runSuccessRateCheck(ejectionTimestamp);
|
this.runSuccessRateCheck(ejectionTimestamp);
|
||||||
this.runFailurePercentageCheck(ejectionTimestamp);
|
this.runFailurePercentageCheck(ejectionTimestamp);
|
||||||
|
|
@ -561,10 +582,21 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer {
|
||||||
);
|
);
|
||||||
this.childBalancer.updateAddressList(addressList, childPolicy, attributes);
|
this.childBalancer.updateAddressList(addressList, childPolicy, attributes);
|
||||||
|
|
||||||
if (this.latestConfig === null || this.latestConfig.getIntervalMs() !== lbConfig.getIntervalMs()) {
|
if (lbConfig.getSuccessRateEjectionConfig() || lbConfig.getFailurePercentageEjectionConfig()) {
|
||||||
clearInterval(this.ejectionTimer);
|
if (this.timerStartTime) {
|
||||||
this.ejectionTimer = setInterval(() => this.runChecks(), lbConfig.getIntervalMs());
|
clearTimeout(this.ejectionTimer);
|
||||||
|
const remainingDelay = lbConfig.getIntervalMs() - ((new Date()).getTime() - this.timerStartTime.getTime());
|
||||||
|
this.startTimer(remainingDelay);
|
||||||
|
} else {
|
||||||
|
this.timerStartTime = new Date();
|
||||||
|
this.startTimer(lbConfig.getIntervalMs());
|
||||||
|
this.switchAllBuckets();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.timerStartTime = null;
|
||||||
|
clearTimeout(this.ejectionTimer);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.latestConfig = lbConfig;
|
this.latestConfig = lbConfig;
|
||||||
}
|
}
|
||||||
exitIdle(): void {
|
exitIdle(): void {
|
||||||
|
|
@ -574,6 +606,7 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer {
|
||||||
this.childBalancer.resetBackoff();
|
this.childBalancer.resetBackoff();
|
||||||
}
|
}
|
||||||
destroy(): void {
|
destroy(): void {
|
||||||
|
clearTimeout(this.ejectionTimer);
|
||||||
this.childBalancer.destroy();
|
this.childBalancer.destroy();
|
||||||
}
|
}
|
||||||
getTypeName(): string {
|
getTypeName(): string {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue