Skip to content

Commit c06189e

Browse files
feat: deferred client initialization (#384)
This PR includes changes from googleapis/gapic-generator-typescript#317 that will move the asynchronous initialization and authentication from the client constructor to an `initialize()` method. This method will be automatically called when the first RPC call is performed. The client library usage has not changed, there is no need to update any code. If you want to make sure the client is authenticated _before_ the first RPC call, you can do ```js await client.initialize(); ``` manually before calling any client method.
1 parent 8323de8 commit c06189e

File tree

5 files changed

+190
-58
lines changed

5 files changed

+190
-58
lines changed

packages/google-cloud-language/src/v1/language_service_client.ts

+53-20
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,13 @@ export class LanguageServiceClient {
4141
private _descriptors: Descriptors = {page: {}, stream: {}, longrunning: {}};
4242
private _innerApiCalls: {[name: string]: Function};
4343
private _terminated = false;
44+
private _opts: ClientOptions;
45+
private _gaxModule: typeof gax | typeof gax.fallback;
46+
private _gaxGrpc: gax.GrpcClient | gax.fallback.GrpcClient;
47+
private _protos: {};
48+
private _defaults: {[method: string]: gax.CallSettings};
4449
auth: gax.GoogleAuth;
45-
languageServiceStub: Promise<{[name: string]: Function}>;
50+
languageServiceStub?: Promise<{[name: string]: Function}>;
4651

4752
/**
4853
* Construct an instance of LanguageServiceClient.
@@ -66,8 +71,6 @@ export class LanguageServiceClient {
6671
* app is running in an environment which supports
6772
* {@link https://developers.google.com/identity/protocols/application-default-credentials Application Default Credentials},
6873
* your project ID will be detected automatically.
69-
* @param {function} [options.promise] - Custom promise module to use instead
70-
* of native Promises.
7174
* @param {string} [options.apiEndpoint] - The domain name of the
7275
* API remote host.
7376
*/
@@ -97,25 +100,28 @@ export class LanguageServiceClient {
97100
// If we are in browser, we are already using fallback because of the
98101
// "browser" field in package.json.
99102
// But if we were explicitly requested to use fallback, let's do it now.
100-
const gaxModule = !isBrowser && opts.fallback ? gax.fallback : gax;
103+
this._gaxModule = !isBrowser && opts.fallback ? gax.fallback : gax;
101104

102105
// Create a `gaxGrpc` object, with any grpc-specific options
103106
// sent to the client.
104107
opts.scopes = (this.constructor as typeof LanguageServiceClient).scopes;
105-
const gaxGrpc = new gaxModule.GrpcClient(opts);
108+
this._gaxGrpc = new this._gaxModule.GrpcClient(opts);
109+
110+
// Save options to use in initialize() method.
111+
this._opts = opts;
106112

107113
// Save the auth object to the client, for use by other methods.
108-
this.auth = gaxGrpc.auth as gax.GoogleAuth;
114+
this.auth = this._gaxGrpc.auth as gax.GoogleAuth;
109115

110116
// Determine the client header string.
111-
const clientHeader = [`gax/${gaxModule.version}`, `gapic/${version}`];
117+
const clientHeader = [`gax/${this._gaxModule.version}`, `gapic/${version}`];
112118
if (typeof process !== 'undefined' && 'versions' in process) {
113119
clientHeader.push(`gl-node/${process.versions.node}`);
114120
} else {
115-
clientHeader.push(`gl-web/${gaxModule.version}`);
121+
clientHeader.push(`gl-web/${this._gaxModule.version}`);
116122
}
117123
if (!opts.fallback) {
118-
clientHeader.push(`grpc/${gaxGrpc.grpcVersion}`);
124+
clientHeader.push(`grpc/${this._gaxGrpc.grpcVersion}`);
119125
}
120126
if (opts.libName && opts.libVersion) {
121127
clientHeader.push(`${opts.libName}/${opts.libVersion}`);
@@ -131,12 +137,12 @@ export class LanguageServiceClient {
131137
'protos',
132138
'protos.json'
133139
);
134-
const protos = gaxGrpc.loadProto(
140+
this._protos = this._gaxGrpc.loadProto(
135141
opts.fallback ? require('../../protos/protos.json') : nodejsProtoPath
136142
);
137143

138144
// Put together the default options sent with requests.
139-
const defaults = gaxGrpc.constructSettings(
145+
this._defaults = this._gaxGrpc.constructSettings(
140146
'google.cloud.language.v1.LanguageService',
141147
gapicConfig as gax.ClientConfig,
142148
opts.clientConfig || {},
@@ -147,17 +153,35 @@ export class LanguageServiceClient {
147153
// of calling the API is handled in `google-gax`, with this code
148154
// merely providing the destination and request information.
149155
this._innerApiCalls = {};
156+
}
157+
158+
/**
159+
* Initialize the client.
160+
* Performs asynchronous operations (such as authentication) and prepares the client.
161+
* This function will be called automatically when any class method is called for the
162+
* first time, but if you need to initialize it before calling an actual method,
163+
* feel free to call initialize() directly.
164+
*
165+
* You can await on this method if you want to make sure the client is initialized.
166+
*
167+
* @returns {Promise} A promise that resolves to an authenticated service stub.
168+
*/
169+
initialize() {
170+
// If the client stub promise is already initialized, return immediately.
171+
if (this.languageServiceStub) {
172+
return this.languageServiceStub;
173+
}
150174

151175
// Put together the "service stub" for
152176
// google.cloud.language.v1.LanguageService.
153-
this.languageServiceStub = gaxGrpc.createStub(
154-
opts.fallback
155-
? (protos as protobuf.Root).lookupService(
177+
this.languageServiceStub = this._gaxGrpc.createStub(
178+
this._opts.fallback
179+
? (this._protos as protobuf.Root).lookupService(
156180
'google.cloud.language.v1.LanguageService'
157181
)
158182
: // tslint:disable-next-line no-any
159-
(protos as any).google.cloud.language.v1.LanguageService,
160-
opts
183+
(this._protos as any).google.cloud.language.v1.LanguageService,
184+
this._opts
161185
) as Promise<{[method: string]: Function}>;
162186

163187
// Iterate over each of the methods that the service provides
@@ -184,9 +208,9 @@ export class LanguageServiceClient {
184208
}
185209
);
186210

187-
const apiCall = gaxModule.createApiCall(
211+
const apiCall = this._gaxModule.createApiCall(
188212
innerCallPromise,
189-
defaults[methodName],
213+
this._defaults[methodName],
190214
this._descriptors.page[methodName] ||
191215
this._descriptors.stream[methodName] ||
192216
this._descriptors.longrunning[methodName]
@@ -200,6 +224,8 @@ export class LanguageServiceClient {
200224
return apiCall(argument, callOptions, callback);
201225
};
202226
}
227+
228+
return this.languageServiceStub;
203229
}
204230

205231
/**
@@ -320,6 +346,7 @@ export class LanguageServiceClient {
320346
options = optionsOrCallback as gax.CallOptions;
321347
}
322348
options = options || {};
349+
this.initialize();
323350
return this._innerApiCalls.analyzeSentiment(request, options, callback);
324351
}
325352
analyzeEntities(
@@ -389,6 +416,7 @@ export class LanguageServiceClient {
389416
options = optionsOrCallback as gax.CallOptions;
390417
}
391418
options = options || {};
419+
this.initialize();
392420
return this._innerApiCalls.analyzeEntities(request, options, callback);
393421
}
394422
analyzeEntitySentiment(
@@ -415,7 +443,7 @@ export class LanguageServiceClient {
415443
>
416444
): void;
417445
/**
418-
* Finds entities, similar to [AnalyzeEntities][google.cloud.language.v1.LanguageService.AnalyzeEntities] in the text and analyzes
446+
* Finds entities, similar to {@link google.cloud.language.v1.LanguageService.AnalyzeEntities|AnalyzeEntities} in the text and analyzes
419447
* sentiment associated with each entity and its mentions.
420448
*
421449
* @param {Object} request
@@ -465,6 +493,7 @@ export class LanguageServiceClient {
465493
options = optionsOrCallback as gax.CallOptions;
466494
}
467495
options = options || {};
496+
this.initialize();
468497
return this._innerApiCalls.analyzeEntitySentiment(
469498
request,
470499
options,
@@ -538,6 +567,7 @@ export class LanguageServiceClient {
538567
options = optionsOrCallback as gax.CallOptions;
539568
}
540569
options = options || {};
570+
this.initialize();
541571
return this._innerApiCalls.analyzeSyntax(request, options, callback);
542572
}
543573
classifyText(
@@ -602,6 +632,7 @@ export class LanguageServiceClient {
602632
options = optionsOrCallback as gax.CallOptions;
603633
}
604634
options = options || {};
635+
this.initialize();
605636
return this._innerApiCalls.classifyText(request, options, callback);
606637
}
607638
annotateText(
@@ -671,6 +702,7 @@ export class LanguageServiceClient {
671702
options = optionsOrCallback as gax.CallOptions;
672703
}
673704
options = options || {};
705+
this.initialize();
674706
return this._innerApiCalls.annotateText(request, options, callback);
675707
}
676708

@@ -680,8 +712,9 @@ export class LanguageServiceClient {
680712
* The client will no longer be usable and all future behavior is undefined.
681713
*/
682714
close(): Promise<void> {
715+
this.initialize();
683716
if (!this._terminated) {
684-
return this.languageServiceStub.then(stub => {
717+
return this.languageServiceStub!.then(stub => {
685718
this._terminated = true;
686719
stub.close();
687720
});

0 commit comments

Comments
 (0)