Skip to content

Commit 62480fc

Browse files
silent fail when srv query fail
1 parent 8803f5d commit 62480fc

File tree

1 file changed

+25
-7
lines changed

1 file changed

+25
-7
lines changed

src/ConfigurationClientManager.ts

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export class ConfigurationClientManager {
3535
#replicaCount: number = 0;
3636
#lastFallbackClientRefreshTime: number = 0;
3737
#lastFallbackClientRefreshAttempt: number = 0;
38+
#srvQueryPending: boolean = false;
3839

3940
constructor (
4041
connectionStringOrEndpoint?: string | URL,
@@ -116,7 +117,8 @@ export class ConfigurationClientManager {
116117
(!this.#dynamicClients ||
117118
// All dynamic clients are in backoff means no client is available
118119
this.#dynamicClients.every(client => currentTime < client.backoffEndTime) ||
119-
currentTime >= this.#lastFallbackClientRefreshTime + FALLBACK_CLIENT_REFRESH_EXPIRE_INTERVAL)) {
120+
currentTime >= this.#lastFallbackClientRefreshTime + FALLBACK_CLIENT_REFRESH_EXPIRE_INTERVAL)
121+
) {
120122
this.#lastFallbackClientRefreshAttempt = currentTime;
121123
await this.#discoverFallbackClients(this.endpoint.hostname);
122124
return availableClients.concat(this.#dynamicClients);
@@ -142,17 +144,33 @@ export class ConfigurationClientManager {
142144
}
143145

144146
async #discoverFallbackClients(host: string) {
145-
let result;
146-
let timeout;
147+
if (this.#srvQueryPending) {
148+
return;
149+
}
150+
this.#srvQueryPending = true;
151+
let result, timeoutId;
147152
try {
153+
// Promise.race will not terminate the pending promises.
154+
// This is a known issue in JavaScript and there is no good solution for it.
155+
// We need to make sure the scale of the potential memory leak is controllable.
156+
const srvQueryPromise = this.#querySrvTargetHost(host);
157+
// There is no way to check the promise status synchronously, so we need to set the flag through the callback.
158+
srvQueryPromise
159+
.then(() => this.#srvQueryPending = false) // resolved
160+
.catch(() => this.#srvQueryPending = false); // rejected
161+
// If the srvQueryPromise is rejected before timeout, the error will be caught in the catch block.
162+
// Otherwise, the timeout error will be caught in the catch block and the srvQueryPromise rejection will be ignored.
148163
result = await Promise.race([
149-
new Promise((_, reject) => timeout = setTimeout(() => reject(new Error("SRV record query timed out.")), SRV_QUERY_TIMEOUT)),
150-
this.#querySrvTargetHost(host)
164+
new Promise((_, reject) =>
165+
timeoutId = setTimeout(() => reject(new Error("SRV record query timed out.")), SRV_QUERY_TIMEOUT)),
166+
srvQueryPromise
151167
]);
152168
} catch (error) {
153-
throw new Error(`Failed to build fallback clients, ${error.message}`);
169+
console.warn(`Failed to build fallback clients, ${error.message}`);
170+
this.#lastFallbackClientRefreshTime = Date.now();
171+
return; // silently fail when SRV record query times out
154172
} finally {
155-
clearTimeout(timeout);
173+
clearTimeout(timeoutId);
156174
}
157175

158176
const srvTargetHosts = shuffleList(result) as string[];

0 commit comments

Comments
 (0)