-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: deferred initialization #317
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,8 +37,13 @@ export class BigQueryStorageClient { | |
private _innerApiCalls: {[name: string]: Function}; | ||
private _pathTemplates: {[name: string]: gax.PathTemplate}; | ||
private _terminated = false; | ||
private _opts: ClientOptions; | ||
private _gaxModule: typeof gax | typeof gax.fallback; | ||
private _gaxGrpc: gax.GrpcClient | gax.fallback.GrpcClient; | ||
private _protos: {}; | ||
private _defaults: {[method: string]: gax.CallSettings}; | ||
auth: gax.GoogleAuth; | ||
bigQueryStorageStub: Promise<{[name: string]: Function}>; | ||
bigQueryStorageStub?: Promise<{[name: string]: Function}>; | ||
|
||
/** | ||
* Construct an instance of BigQueryStorageClient. | ||
|
@@ -89,28 +94,31 @@ export class BigQueryStorageClient { | |
// If we are in browser, we are already using fallback because of the | ||
// "browser" field in package.json. | ||
// But if we were explicitly requested to use fallback, let's do it now. | ||
const gaxModule = !isBrowser && opts.fallback ? gax.fallback : gax; | ||
this._gaxModule = !isBrowser && opts.fallback ? gax.fallback : gax; | ||
|
||
// Create a `gaxGrpc` object, with any grpc-specific options | ||
// sent to the client. | ||
opts.scopes = (this.constructor as typeof BigQueryStorageClient).scopes; | ||
const gaxGrpc = new gaxModule.GrpcClient(opts); | ||
this._gaxGrpc = new this._gaxModule.GrpcClient(opts); | ||
|
||
// Save options to use in initialize() method. | ||
this._opts = opts; | ||
|
||
// Save the auth object to the client, for use by other methods. | ||
this.auth = (gaxGrpc.auth as gax.GoogleAuth); | ||
this.auth = (this._gaxGrpc.auth as gax.GoogleAuth); | ||
|
||
// Determine the client header string. | ||
const clientHeader = [ | ||
`gax/${gaxModule.version}`, | ||
`gax/${this._gaxModule.version}`, | ||
`gapic/${version}`, | ||
]; | ||
if (typeof process !== 'undefined' && 'versions' in process) { | ||
clientHeader.push(`gl-node/${process.versions.node}`); | ||
} else { | ||
clientHeader.push(`gl-web/${gaxModule.version}`); | ||
clientHeader.push(`gl-web/${this._gaxModule.version}`); | ||
} | ||
if (!opts.fallback) { | ||
clientHeader.push(`grpc/${gaxGrpc.grpcVersion}`); | ||
clientHeader.push(`grpc/${this._gaxGrpc.grpcVersion}`); | ||
} | ||
if (opts.libName && opts.libVersion) { | ||
clientHeader.push(`${opts.libName}/${opts.libVersion}`); | ||
|
@@ -120,7 +128,7 @@ export class BigQueryStorageClient { | |
// For browsers, pass the JSON content. | ||
|
||
const nodejsProtoPath = path.join(__dirname, '..', '..', 'protos', 'protos.json'); | ||
const protos = gaxGrpc.loadProto( | ||
this._protos = this._gaxGrpc.loadProto( | ||
opts.fallback ? | ||
require("../../protos/protos.json") : | ||
nodejsProtoPath | ||
|
@@ -130,38 +138,56 @@ export class BigQueryStorageClient { | |
// identifiers to uniquely identify resources within the API. | ||
// Create useful helper objects for these. | ||
this._pathTemplates = { | ||
readSessionPathTemplate: new gaxModule.PathTemplate( | ||
readSessionPathTemplate: new this._gaxModule.PathTemplate( | ||
'projects/{project}/locations/{location}/sessions/{session}' | ||
), | ||
streamPathTemplate: new gaxModule.PathTemplate( | ||
streamPathTemplate: new this._gaxModule.PathTemplate( | ||
'projects/{project}/locations/{location}/streams/{stream}' | ||
), | ||
}; | ||
|
||
// Some of the methods on this service provide streaming responses. | ||
// Provide descriptors for these. | ||
this._descriptors.stream = { | ||
readRows: new gaxModule.StreamDescriptor(gax.StreamType.SERVER_STREAMING) | ||
readRows: new this._gaxModule.StreamDescriptor(gax.StreamType.SERVER_STREAMING) | ||
}; | ||
|
||
// Put together the default options sent with requests. | ||
const defaults = gaxGrpc.constructSettings( | ||
this._defaults = this._gaxGrpc.constructSettings( | ||
'google.cloud.bigquery.storage.v1beta1.BigQueryStorage', gapicConfig as gax.ClientConfig, | ||
opts.clientConfig || {}, {'x-goog-api-client': clientHeader.join(' ')}); | ||
|
||
// Set up a dictionary of "inner API calls"; the core implementation | ||
// of calling the API is handled in `google-gax`, with this code | ||
// merely providing the destination and request information. | ||
this._innerApiCalls = {}; | ||
} | ||
|
||
/** | ||
* Initialize the client. | ||
* Performs asynchronous operations (such as authentication) and prepares the client. | ||
* This function will be called automatically when any class method is called for the | ||
* first time, but if you need to initialize it before calling an actual method, | ||
* feel free to call initialize() directly. | ||
* | ||
* You can await on this method if you want to make sure the client is initialized. | ||
* | ||
* @returns {Promise} A promise that resolves to an authenticated service stub. | ||
*/ | ||
initialize() { | ||
// If the client stub promise is already initialized, return immediately. | ||
if (this.bigQueryStorageStub) { | ||
return this.bigQueryStorageStub; | ||
} | ||
|
||
// Put together the "service stub" for | ||
// google.cloud.bigquery.storage.v1beta1.BigQueryStorage. | ||
this.bigQueryStorageStub = gaxGrpc.createStub( | ||
opts.fallback ? | ||
(protos as protobuf.Root).lookupService('google.cloud.bigquery.storage.v1beta1.BigQueryStorage') : | ||
this.bigQueryStorageStub = this._gaxGrpc.createStub( | ||
this._opts.fallback ? | ||
(this._protos as protobuf.Root).lookupService('google.cloud.bigquery.storage.v1beta1.BigQueryStorage') : | ||
// tslint:disable-next-line no-any | ||
(protos as any).google.cloud.bigquery.storage.v1beta1.BigQueryStorage, | ||
opts) as Promise<{[method: string]: Function}>; | ||
(this._protos as any).google.cloud.bigquery.storage.v1beta1.BigQueryStorage, | ||
this._opts) as Promise<{[method: string]: Function}>; | ||
|
||
// Iterate over each of the methods that the service provides | ||
// and create an API call method for each. | ||
|
@@ -180,9 +206,9 @@ export class BigQueryStorageClient { | |
throw err; | ||
}); | ||
|
||
const apiCall = gaxModule.createApiCall( | ||
const apiCall = this._gaxModule.createApiCall( | ||
innerCallPromise, | ||
defaults[methodName], | ||
this._defaults[methodName], | ||
this._descriptors.page[methodName] || | ||
this._descriptors.stream[methodName] || | ||
this._descriptors.longrunning[methodName] | ||
|
@@ -196,6 +222,8 @@ export class BigQueryStorageClient { | |
return apiCall(argument, callOptions, callback); | ||
}; | ||
} | ||
|
||
return this.bigQueryStorageStub; | ||
} | ||
|
||
/** | ||
|
@@ -341,6 +369,7 @@ export class BigQueryStorageClient { | |
'table_reference.project_id': request.tableReference!.projectId || '', | ||
'table_reference.dataset_id': request.tableReference!.datasetId || '', | ||
}); | ||
this.initialize(); | ||
return this._innerApiCalls.createReadSession(request, options, callback); | ||
} | ||
batchCreateReadSessionStreams( | ||
|
@@ -407,6 +436,7 @@ export class BigQueryStorageClient { | |
] = gax.routingHeader.fromParams({ | ||
'session.name': request.session!.name || '', | ||
}); | ||
this.initialize(); | ||
return this._innerApiCalls.batchCreateReadSessionStreams(request, options, callback); | ||
} | ||
finalizeStream( | ||
|
@@ -479,6 +509,7 @@ export class BigQueryStorageClient { | |
] = gax.routingHeader.fromParams({ | ||
'stream.name': request.stream!.name || '', | ||
}); | ||
this.initialize(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this this potentially be:
It seems like we're still potentially creating promises that are unhandled, or maybe I'm missing something? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, this does not change. We won't be able to make it perfect until we stop supporting callbacks. But now it can be more predictable since users can do There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another problem is that the method must immediately return a cancellable call that comes from Gax, not just a promise that eventually resolves to a result. This use case:
|
||
return this._innerApiCalls.finalizeStream(request, options, callback); | ||
} | ||
splitReadStream( | ||
|
@@ -558,6 +589,7 @@ export class BigQueryStorageClient { | |
] = gax.routingHeader.fromParams({ | ||
'original_stream.name': request.originalStream!.name || '', | ||
}); | ||
this.initialize(); | ||
return this._innerApiCalls.splitReadStream(request, options, callback); | ||
} | ||
|
||
|
@@ -596,6 +628,7 @@ export class BigQueryStorageClient { | |
] = gax.routingHeader.fromParams({ | ||
'read_position.stream.name': request.readPosition!.stream!.name || '', | ||
}); | ||
this.initialize(); | ||
return this._innerApiCalls.readRows(request, options); | ||
} | ||
|
||
|
@@ -707,8 +740,9 @@ export class BigQueryStorageClient { | |
* The client will no longer be usable and all future behavior is undefined. | ||
*/ | ||
close(): Promise<void> { | ||
this.initialize(); | ||
if (!this._terminated) { | ||
return this.bigQueryStorageStub.then(stub => { | ||
return this.bigQueryStorageStub!.then(stub => { | ||
this._terminated = true; | ||
stub.close(); | ||
}); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume
this._gaxModule.createApiCall
, doesinitialize
not get called when younew
a client?