@@ -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,37 +107,45 @@ export class CloudSQLInstance {
106
107
} ) as ReturnType < typeof pThrottle > ;
107
108
}
108
109
109
- forceRefresh ( ) {
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 ;
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
124
this . scheduleRefresh ( 0 ) ;
117
- }
118
125
119
- // refreshComplete Returns a promise that resolves when the current refresh
120
- // cycle has completed, either with success or failure. If no refresh is
121
- // in progress, the promise will resolve immediately.
122
- refreshComplete ( ) : Promise < void > {
123
- return new Promise ( ( resolve ) => {
126
+ return new Promise ( resolve => {
124
127
// setTimeout() to yield execution to allow other refresh background
125
- // tasks to start.
126
- setTimeout ( ( ) => {
127
- if ( this . next ) {
128
+ // task to start.
129
+ setTimeout ( ( ) => {
130
+ if ( this . next ) {
128
131
// If there is a refresh promise in progress, resolve this promise
129
132
// when the refresh is complete.
130
- this . next . finally ( resolve )
133
+ this . next . finally ( resolve ) ;
131
134
} else {
132
135
// Else resolve immediately.
133
- resolve ( )
136
+ resolve ( ) ;
134
137
}
135
138
} , 0 ) ;
136
139
} ) ;
137
140
}
138
141
139
142
refresh ( ) : Promise < RefreshResult > {
143
+ if ( this . closed ) {
144
+ this . scheduledRefreshID = undefined ;
145
+ this . next = undefined ;
146
+ return Promise . reject ( 'closed' ) ;
147
+ }
148
+
140
149
const currentRefreshId = this . scheduledRefreshID ;
141
150
142
151
// Since forceRefresh might be invoked during an ongoing refresh
@@ -203,6 +212,12 @@ export class CloudSQLInstance {
203
212
// used to create new connections to a Cloud SQL instance. It throws in
204
213
// case any of the internal steps fails.
205
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
+
206
221
const rsaKeys : RSAKeys = await generateKeys ( ) ;
207
222
const metadata : InstanceMetadata =
208
223
await this . sqlAdminFetcher . getInstanceMetadata ( this . instanceInfo ) ;
@@ -264,6 +279,9 @@ export class CloudSQLInstance {
264
279
}
265
280
266
281
private scheduleRefresh ( delay : number ) : void {
282
+ if ( this . closed ) {
283
+ return ;
284
+ }
267
285
this . scheduledRefreshID = setTimeout ( ( ) => this . refresh ( ) , delay ) ;
268
286
}
269
287
@@ -280,4 +298,11 @@ export class CloudSQLInstance {
280
298
setEstablishedConnection ( ) : void {
281
299
this . establishedConnection = true ;
282
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
+ }
283
308
}
0 commit comments