1 | "use strict";
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 | Object.defineProperty(exports, "__esModule", { value: true });
|
19 | exports.setup = exports.RoundRobinLoadBalancer = void 0;
|
20 | const load_balancer_1 = require("./load-balancer");
|
21 | const connectivity_state_1 = require("./connectivity-state");
|
22 | const picker_1 = require("./picker");
|
23 | const subchannel_address_1 = require("./subchannel-address");
|
24 | const logging = require("./logging");
|
25 | const constants_1 = require("./constants");
|
26 | const TRACER_NAME = 'round_robin';
|
27 | function trace(text) {
|
28 | logging.trace(constants_1.LogVerbosity.DEBUG, TRACER_NAME, text);
|
29 | }
|
30 | const TYPE_NAME = 'round_robin';
|
31 | class RoundRobinLoadBalancingConfig {
|
32 | getLoadBalancerName() {
|
33 | return TYPE_NAME;
|
34 | }
|
35 | constructor() { }
|
36 | toJsonObject() {
|
37 | return {
|
38 | [TYPE_NAME]: {},
|
39 | };
|
40 | }
|
41 |
|
42 | static createFromJson(obj) {
|
43 | return new RoundRobinLoadBalancingConfig();
|
44 | }
|
45 | }
|
46 | class RoundRobinPicker {
|
47 | constructor(subchannelList, nextIndex = 0) {
|
48 | this.subchannelList = subchannelList;
|
49 | this.nextIndex = nextIndex;
|
50 | }
|
51 | pick(pickArgs) {
|
52 | const pickedSubchannel = this.subchannelList[this.nextIndex];
|
53 | this.nextIndex = (this.nextIndex + 1) % this.subchannelList.length;
|
54 | return {
|
55 | pickResultType: picker_1.PickResultType.COMPLETE,
|
56 | subchannel: pickedSubchannel,
|
57 | status: null,
|
58 | extraFilterFactories: [],
|
59 | onCallStarted: null,
|
60 | };
|
61 | }
|
62 | |
63 |
|
64 |
|
65 |
|
66 |
|
67 | peekNextSubchannel() {
|
68 | return this.subchannelList[this.nextIndex];
|
69 | }
|
70 | }
|
71 | class RoundRobinLoadBalancer {
|
72 | constructor(channelControlHelper) {
|
73 | this.channelControlHelper = channelControlHelper;
|
74 | this.subchannels = [];
|
75 | this.currentState = connectivity_state_1.ConnectivityState.IDLE;
|
76 | this.currentReadyPicker = null;
|
77 | this.subchannelStateCounts = {
|
78 | [connectivity_state_1.ConnectivityState.CONNECTING]: 0,
|
79 | [connectivity_state_1.ConnectivityState.IDLE]: 0,
|
80 | [connectivity_state_1.ConnectivityState.READY]: 0,
|
81 | [connectivity_state_1.ConnectivityState.SHUTDOWN]: 0,
|
82 | [connectivity_state_1.ConnectivityState.TRANSIENT_FAILURE]: 0,
|
83 | };
|
84 | this.subchannelStateListener = (subchannel, previousState, newState) => {
|
85 | this.subchannelStateCounts[previousState] -= 1;
|
86 | this.subchannelStateCounts[newState] += 1;
|
87 | this.calculateAndUpdateState();
|
88 | if (newState === connectivity_state_1.ConnectivityState.TRANSIENT_FAILURE ||
|
89 | newState === connectivity_state_1.ConnectivityState.IDLE) {
|
90 | this.channelControlHelper.requestReresolution();
|
91 | subchannel.startConnecting();
|
92 | }
|
93 | };
|
94 | }
|
95 | calculateAndUpdateState() {
|
96 | if (this.subchannelStateCounts[connectivity_state_1.ConnectivityState.READY] > 0) {
|
97 | const readySubchannels = this.subchannels.filter((subchannel) => subchannel.getConnectivityState() === connectivity_state_1.ConnectivityState.READY);
|
98 | let index = 0;
|
99 | if (this.currentReadyPicker !== null) {
|
100 | index = readySubchannels.indexOf(this.currentReadyPicker.peekNextSubchannel());
|
101 | if (index < 0) {
|
102 | index = 0;
|
103 | }
|
104 | }
|
105 | this.updateState(connectivity_state_1.ConnectivityState.READY, new RoundRobinPicker(readySubchannels, index));
|
106 | }
|
107 | else if (this.subchannelStateCounts[connectivity_state_1.ConnectivityState.CONNECTING] > 0) {
|
108 | this.updateState(connectivity_state_1.ConnectivityState.CONNECTING, new picker_1.QueuePicker(this));
|
109 | }
|
110 | else if (this.subchannelStateCounts[connectivity_state_1.ConnectivityState.TRANSIENT_FAILURE] > 0) {
|
111 | this.updateState(connectivity_state_1.ConnectivityState.TRANSIENT_FAILURE, new picker_1.UnavailablePicker());
|
112 | }
|
113 | else {
|
114 | this.updateState(connectivity_state_1.ConnectivityState.IDLE, new picker_1.QueuePicker(this));
|
115 | }
|
116 | }
|
117 | updateState(newState, picker) {
|
118 | trace(connectivity_state_1.ConnectivityState[this.currentState] +
|
119 | ' -> ' +
|
120 | connectivity_state_1.ConnectivityState[newState]);
|
121 | if (newState === connectivity_state_1.ConnectivityState.READY) {
|
122 | this.currentReadyPicker = picker;
|
123 | }
|
124 | else {
|
125 | this.currentReadyPicker = null;
|
126 | }
|
127 | this.currentState = newState;
|
128 | this.channelControlHelper.updateState(newState, picker);
|
129 | }
|
130 | resetSubchannelList() {
|
131 | for (const subchannel of this.subchannels) {
|
132 | subchannel.removeConnectivityStateListener(this.subchannelStateListener);
|
133 | subchannel.unref();
|
134 | this.channelControlHelper.removeChannelzChild(subchannel.getChannelzRef());
|
135 | }
|
136 | this.subchannelStateCounts = {
|
137 | [connectivity_state_1.ConnectivityState.CONNECTING]: 0,
|
138 | [connectivity_state_1.ConnectivityState.IDLE]: 0,
|
139 | [connectivity_state_1.ConnectivityState.READY]: 0,
|
140 | [connectivity_state_1.ConnectivityState.SHUTDOWN]: 0,
|
141 | [connectivity_state_1.ConnectivityState.TRANSIENT_FAILURE]: 0,
|
142 | };
|
143 | this.subchannels = [];
|
144 | }
|
145 | updateAddressList(addressList, lbConfig) {
|
146 | this.resetSubchannelList();
|
147 | trace('Connect to address list ' +
|
148 | addressList.map((address) => subchannel_address_1.subchannelAddressToString(address)));
|
149 | this.subchannels = addressList.map((address) => this.channelControlHelper.createSubchannel(address, {}));
|
150 | for (const subchannel of this.subchannels) {
|
151 | subchannel.ref();
|
152 | subchannel.addConnectivityStateListener(this.subchannelStateListener);
|
153 | this.channelControlHelper.addChannelzChild(subchannel.getChannelzRef());
|
154 | const subchannelState = subchannel.getConnectivityState();
|
155 | this.subchannelStateCounts[subchannelState] += 1;
|
156 | if (subchannelState === connectivity_state_1.ConnectivityState.IDLE ||
|
157 | subchannelState === connectivity_state_1.ConnectivityState.TRANSIENT_FAILURE) {
|
158 | subchannel.startConnecting();
|
159 | }
|
160 | }
|
161 | this.calculateAndUpdateState();
|
162 | }
|
163 | exitIdle() {
|
164 | for (const subchannel of this.subchannels) {
|
165 | subchannel.startConnecting();
|
166 | }
|
167 | }
|
168 | resetBackoff() {
|
169 | |
170 |
|
171 | }
|
172 | destroy() {
|
173 | this.resetSubchannelList();
|
174 | }
|
175 | getTypeName() {
|
176 | return TYPE_NAME;
|
177 | }
|
178 | }
|
179 | exports.RoundRobinLoadBalancer = RoundRobinLoadBalancer;
|
180 | function setup() {
|
181 | load_balancer_1.registerLoadBalancerType(TYPE_NAME, RoundRobinLoadBalancer, RoundRobinLoadBalancingConfig);
|
182 | }
|
183 | exports.setup = setup;
|
184 |
|
\ | No newline at end of file |