Skip to content

Commit 243ce28

Browse files
authored
feat: Group Concurrent getClient Requests (#1848)
1 parent 5fc3bcc commit 243ce28

File tree

2 files changed

+42
-1
lines changed

2 files changed

+42
-1
lines changed

src/auth/googleauth.ts

+20-1
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,10 @@ export class GoogleAuth<T extends AuthClient = JSONClient> {
187187
apiKey: string | null;
188188

189189
cachedCredential: AnyAuthClient | T | null = null;
190+
/**
191+
* A pending {@link AuthClient}. Used for concurrent {@link GoogleAuth.getClient} calls.
192+
*/
193+
#pendingAuthClient: Promise<AnyAuthClient | T> | null = null;
190194

191195
/**
192196
* Scopes populated by the client library by default. We differentiate between
@@ -1007,7 +1011,22 @@ export class GoogleAuth<T extends AuthClient = JSONClient> {
10071011
async getClient(): Promise<AnyAuthClient | T> {
10081012
if (this.cachedCredential) {
10091013
return this.cachedCredential;
1010-
} else if (this.jsonContent) {
1014+
}
1015+
1016+
// Use an existing auth client request, or cache a new one
1017+
this.#pendingAuthClient =
1018+
this.#pendingAuthClient || this.#determineClient();
1019+
1020+
try {
1021+
return await this.#pendingAuthClient;
1022+
} finally {
1023+
// reset the pending auth client in case it is changed later
1024+
this.#pendingAuthClient = null;
1025+
}
1026+
}
1027+
1028+
async #determineClient() {
1029+
if (this.jsonContent) {
10111030
return this._cacheClientFromJSON(this.jsonContent, this.clientOptions);
10121031
} else if (this.keyFilename) {
10131032
const filePath = path.resolve(this.keyFilename);

test/test.googleauth.ts

+22
Original file line numberDiff line numberDiff line change
@@ -2617,6 +2617,28 @@ describe('googleauth', () => {
26172617

26182618
assert(actualClient instanceof ExternalAccountAuthorizedUserClient);
26192619
});
2620+
2621+
it('should return the same instance for concurrent requests', async () => {
2622+
// Set up a mock to return path to a valid credentials file.
2623+
mockEnvVar(
2624+
'GOOGLE_APPLICATION_CREDENTIALS',
2625+
'./test/fixtures/external-account-authorized-user-cred.json'
2626+
);
2627+
const auth = new GoogleAuth();
2628+
2629+
let client: AuthClient | null = null;
2630+
const getClientCalls = await Promise.all([
2631+
auth.getClient(),
2632+
auth.getClient(),
2633+
auth.getClient(),
2634+
]);
2635+
2636+
for (const resClient of getClientCalls) {
2637+
if (!client) client = resClient;
2638+
2639+
assert(client === resClient);
2640+
}
2641+
});
26202642
});
26212643

26222644
describe('sign()', () => {

0 commit comments

Comments
 (0)