@@ -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,7 +107,7 @@ export class CloudSQLInstance {
106
107
} ) as ReturnType < typeof pThrottle > ;
107
108
}
108
109
109
- forceRefresh ( ) {
110
+ forceRefresh ( ) {
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 ) {
@@ -120,23 +121,29 @@ export class CloudSQLInstance {
120
121
// cycle has completed, either with success or failure. If no refresh is
121
122
// in progress, the promise will resolve immediately.
122
123
refreshComplete ( ) : Promise < void > {
123
- return new Promise ( ( resolve ) => {
124
+ return new Promise ( resolve => {
124
125
// setTimeout() to yield execution to allow other refresh background
125
126
// tasks to start.
126
- setTimeout ( ( ) => {
127
- if ( this . next ) {
127
+ setTimeout ( ( ) => {
128
+ if ( this . next ) {
128
129
// If there is a refresh promise in progress, resolve this promise
129
130
// when the refresh is complete.
130
- this . next . finally ( resolve )
131
+ this . next . finally ( resolve ) ;
131
132
} else {
132
133
// Else resolve immediately.
133
- resolve ( )
134
+ resolve ( ) ;
134
135
}
135
136
} , 0 ) ;
136
137
} ) ;
137
138
}
138
139
139
140
refresh ( ) : Promise < RefreshResult > {
141
+ if ( this . closed ) {
142
+ this . scheduledRefreshID = undefined ;
143
+ this . next = undefined ;
144
+ return Promise . reject ( 'closed' ) ;
145
+ }
146
+
140
147
const currentRefreshId = this . scheduledRefreshID ;
141
148
142
149
// Since forceRefresh might be invoked during an ongoing refresh
@@ -203,6 +210,12 @@ export class CloudSQLInstance {
203
210
// used to create new connections to a Cloud SQL instance. It throws in
204
211
// case any of the internal steps fails.
205
212
private async performRefresh ( ) : Promise < RefreshResult > {
213
+ if ( this . closed ) {
214
+ // performRefresh() could be delayed by the rate limiter. So
215
+ // this instance may have been closed.
216
+ return Promise . reject ( 'closed' ) ;
217
+ }
218
+
206
219
const rsaKeys : RSAKeys = await generateKeys ( ) ;
207
220
const metadata : InstanceMetadata =
208
221
await this . sqlAdminFetcher . getInstanceMetadata ( this . instanceInfo ) ;
@@ -264,6 +277,9 @@ export class CloudSQLInstance {
264
277
}
265
278
266
279
private scheduleRefresh ( delay : number ) : void {
280
+ if ( this . closed ) {
281
+ return ;
282
+ }
267
283
this . scheduledRefreshID = setTimeout ( ( ) => this . refresh ( ) , delay ) ;
268
284
}
269
285
@@ -280,4 +296,11 @@ export class CloudSQLInstance {
280
296
setEstablishedConnection ( ) : void {
281
297
this . establishedConnection = true ;
282
298
}
299
+
300
+ // close stops any refresh process in progress and prevents future refresh
301
+ // connections.
302
+ close ( ) : void {
303
+ this . closed = true ;
304
+ this . cancelRefresh ( ) ;
305
+ }
283
306
}
0 commit comments