@@ -69,6 +69,7 @@ export class CloudSQLInstance {
69
69
private scheduledRefreshID ?: ReturnType < typeof setTimeout > | null = undefined ;
70
70
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
71
71
private throttle ?: any ;
72
+ private closed = false ;
72
73
public readonly instanceInfo : InstanceConnectionInfo ;
73
74
public ephemeralCert ?: SslCert ;
74
75
public host ?: string ;
@@ -106,17 +107,45 @@ export class CloudSQLInstance {
106
107
} ) as ReturnType < typeof pThrottle > ;
107
108
}
108
109
109
- forceRefresh ( ) : Promise < RefreshResult > {
110
+ forceRefresh ( ) : Promise < void > {
110
111
// if a refresh is already ongoing, just await for its promise to fulfill
111
112
// so that a new instance info is available before reconnecting
112
113
if ( this . next ) {
113
- return this . next ;
114
+ return new Promise ( resolve => {
115
+ if ( this . next ) {
116
+ this . next . finally ( resolve ) ;
117
+ } else {
118
+ resolve ( ) ;
119
+ }
120
+ } ) ;
114
121
}
122
+
115
123
this . cancelRefresh ( ) ;
116
- return this . refresh ( ) ;
124
+ this . scheduleRefresh ( 0 ) ;
125
+
126
+ return new Promise ( resolve => {
127
+ // setTimeout() to yield execution to allow other refresh background
128
+ // task to start.
129
+ setTimeout ( ( ) => {
130
+ if ( this . next ) {
131
+ // If there is a refresh promise in progress, resolve this promise
132
+ // when the refresh is complete.
133
+ this . next . finally ( resolve ) ;
134
+ } else {
135
+ // Else resolve immediately.
136
+ resolve ( ) ;
137
+ }
138
+ } , 0 ) ;
139
+ } ) ;
117
140
}
118
141
119
142
refresh ( ) : Promise < RefreshResult > {
143
+ if ( this . closed ) {
144
+ this . scheduledRefreshID = undefined ;
145
+ this . next = undefined ;
146
+ return Promise . reject ( 'closed' ) ;
147
+ }
148
+
120
149
const currentRefreshId = this . scheduledRefreshID ;
121
150
122
151
// Since forceRefresh might be invoked during an ongoing refresh
@@ -183,6 +212,12 @@ export class CloudSQLInstance {
183
212
// used to create new connections to a Cloud SQL instance. It throws in
184
213
// case any of the internal steps fails.
185
214
private async performRefresh ( ) : Promise < RefreshResult > {
215
+ if ( this . closed ) {
216
+ // The connector may be closed while the rate limiter delayed
217
+ // a call to performRefresh() so check this.closed before continuing.
218
+ return Promise . reject ( 'closed' ) ;
219
+ }
220
+
186
221
const rsaKeys : RSAKeys = await generateKeys ( ) ;
187
222
const metadata : InstanceMetadata =
188
223
await this . sqlAdminFetcher . getInstanceMetadata ( this . instanceInfo ) ;
@@ -244,6 +279,9 @@ export class CloudSQLInstance {
244
279
}
245
280
246
281
private scheduleRefresh ( delay : number ) : void {
282
+ if ( this . closed ) {
283
+ return ;
284
+ }
247
285
this . scheduledRefreshID = setTimeout ( ( ) => this . refresh ( ) , delay ) ;
248
286
}
249
287
@@ -260,4 +298,11 @@ export class CloudSQLInstance {
260
298
setEstablishedConnection ( ) : void {
261
299
this . establishedConnection = true ;
262
300
}
301
+
302
+ // close stops any refresh process in progress and prevents future refresh
303
+ // connections.
304
+ close ( ) : void {
305
+ this . closed = true ;
306
+ this . cancelRefresh ( ) ;
307
+ }
263
308
}
0 commit comments