Skip to content
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 client initialization #23

Merged
merged 1 commit into from
Mar 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 57 additions & 22 deletions src/v1beta1/big_query_storage_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,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.
Expand All @@ -68,8 +73,6 @@ export class BigQueryStorageClient {
* app is running in an environment which supports
* {@link https://developers.google.com/identity/protocols/application-default-credentials Application Default Credentials},
* your project ID will be detected automatically.
* @param {function} [options.promise] - Custom promise module to use instead
* of native Promises.
* @param {string} [options.apiEndpoint] - The domain name of the
* API remote host.
*/
Expand Down Expand Up @@ -99,25 +102,28 @@ 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}`, `gapic/${version}`];
const clientHeader = [`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}`);
Expand All @@ -133,30 +139,32 @@ export class BigQueryStorageClient {
'protos',
'protos.json'
);
const protos = gaxGrpc.loadProto(
this._protos = this._gaxGrpc.loadProto(
opts.fallback ? require('../../protos/protos.json') : nodejsProtoPath
);

// This API contains "path templates"; forward-slash-separated
// 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 || {},
Expand All @@ -167,17 +175,36 @@ export class BigQueryStorageClient {
// 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(
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
(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
Expand All @@ -203,9 +230,9 @@ export class BigQueryStorageClient {
}
);

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]
Expand All @@ -219,6 +246,8 @@ export class BigQueryStorageClient {
return apiCall(argument, callOptions, callback);
};
}

return this.bigQueryStorageStub;
}

/**
Expand Down Expand Up @@ -386,6 +415,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(
Expand Down Expand Up @@ -473,6 +503,7 @@ export class BigQueryStorageClient {
] = gax.routingHeader.fromParams({
'session.name': request.session!.name || '',
});
this.initialize();
return this._innerApiCalls.batchCreateReadSessionStreams(
request,
options,
Expand Down Expand Up @@ -570,6 +601,7 @@ export class BigQueryStorageClient {
] = gax.routingHeader.fromParams({
'stream.name': request.stream!.name || '',
});
this.initialize();
return this._innerApiCalls.finalizeStream(request, options, callback);
}
splitReadStream(
Expand Down Expand Up @@ -670,6 +702,7 @@ export class BigQueryStorageClient {
] = gax.routingHeader.fromParams({
'original_stream.name': request.originalStream!.name || '',
});
this.initialize();
return this._innerApiCalls.splitReadStream(request, options, callback);
}

Expand Down Expand Up @@ -708,6 +741,7 @@ export class BigQueryStorageClient {
] = gax.routingHeader.fromParams({
'read_position.stream.name': request.readPosition!.stream!.name || '',
});
this.initialize();
return this._innerApiCalls.readRows(request, options);
}

Expand Down Expand Up @@ -822,8 +856,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();
});
Expand Down
8 changes: 4 additions & 4 deletions synth.metadata
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"updateTime": "2020-03-05T12:45:42.538924Z",
"updateTime": "2020-03-05T23:02:10.150448Z",
"sources": [
{
"git": {
"name": "googleapis",
"remote": "https://github.com/googleapis/googleapis.git",
"sha": "638253bf86d1ce1c314108a089b7351440c2f0bf",
"internalRef": "298971070",
"log": "638253bf86d1ce1c314108a089b7351440c2f0bf\nfix: add java_multiple_files option for automl text_sentiment.proto\n\nPiperOrigin-RevId: 298971070\n\n373d655703bf914fb8b0b1cc4071d772bac0e0d1\nUpdate Recs AI Beta public bazel file\n\nPiperOrigin-RevId: 298961623\n\ndcc5d00fc8a8d8b56f16194d7c682027b2c66a3b\nfix: add java_multiple_files option for automl classification.proto\n\nPiperOrigin-RevId: 298953301\n\na3f791827266f3496a6a5201d58adc4bb265c2a3\nchore: automl/v1 publish annotations and retry config\n\nPiperOrigin-RevId: 298942178\n\n01c681586d8d6dbd60155289b587aee678530bd9\nMark return_immediately in PullRequest deprecated.\n\nPiperOrigin-RevId: 298893281\n\nc9f5e9c4bfed54bbd09227e990e7bded5f90f31c\nRemove out of date documentation for predicate support on the Storage API\n\nPiperOrigin-RevId: 298883309\n\nfd5b3b8238d783b04692a113ffe07c0363f5de0f\ngenerate webrisk v1 proto\n\nPiperOrigin-RevId: 298847934\n\n541b1ded4abadcc38e8178680b0677f65594ea6f\nUpdate cloud asset api v1p4beta1.\n\nPiperOrigin-RevId: 298686266\n\nc0d171acecb4f5b0bfd2c4ca34fc54716574e300\n Updated to include the Notification v1 API.\n\nPiperOrigin-RevId: 298652775\n\n2346a9186c0bff2c9cc439f2459d558068637e05\nAdd Service Directory v1beta1 protos and configs\n\nPiperOrigin-RevId: 298625638\n\n"
"sha": "f0b581b5bdf803e45201ecdb3688b60e381628a8",
"internalRef": "299181282",
"log": "f0b581b5bdf803e45201ecdb3688b60e381628a8\nfix: recommendationengine/v1beta1 update some comments\n\nPiperOrigin-RevId: 299181282\n\n10e9a0a833dc85ff8f05b2c67ebe5ac785fe04ff\nbuild: add generated BUILD file for Routes Preferred API\n\nPiperOrigin-RevId: 299164808\n\n86738c956a8238d7c77f729be78b0ed887a6c913\npublish v1p1beta1: update with absolute address in comments\n\nPiperOrigin-RevId: 299152383\n\n73d9f2ad4591de45c2e1f352bc99d70cbd2a6d95\npublish v1: update with absolute address in comments\n\nPiperOrigin-RevId: 299147194\n\nd2158f24cb77b0b0ccfe68af784c6a628705e3c6\npublish v1beta2: update with absolute address in comments\n\nPiperOrigin-RevId: 299147086\n\n7fca61292c11b4cd5b352cee1a50bf88819dd63b\npublish v1p2beta1: update with absolute address in comments\n\nPiperOrigin-RevId: 299146903\n\n583b7321624736e2c490e328f4b1957335779295\npublish v1p3beta1: update with absolute address in comments\n\nPiperOrigin-RevId: 299146674\n\n"
}
},
{
Expand Down
36 changes: 36 additions & 0 deletions test/gapic-big_query_storage-v1beta1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,30 @@ describe('v1beta1.BigQueryStorageClient', () => {
});
assert(client);
});
it('has initialize method and supports deferred initialization', async () => {
const client = new bigquerystorageModule.v1beta1.BigQueryStorageClient({
credentials: {client_email: 'bogus', private_key: 'bogus'},
projectId: 'bogus',
});
assert.strictEqual(client.bigQueryStorageStub, undefined);
await client.initialize();
assert(client.bigQueryStorageStub);
});
it('has close method', () => {
const client = new bigquerystorageModule.v1beta1.BigQueryStorageClient({
credentials: {client_email: 'bogus', private_key: 'bogus'},
projectId: 'bogus',
});
client.close();
});
describe('createReadSession', () => {
it('invokes createReadSession without error', done => {
const client = new bigquerystorageModule.v1beta1.BigQueryStorageClient({
credentials: {client_email: 'bogus', private_key: 'bogus'},
projectId: 'bogus',
});
// Initialize client before mocking
client.initialize();
// Mock request
const request: protosTypes.google.cloud.bigquery.storage.v1beta1.ICreateReadSessionRequest = {};
request.tableReference = {};
Expand All @@ -137,6 +155,8 @@ describe('v1beta1.BigQueryStorageClient', () => {
credentials: {client_email: 'bogus', private_key: 'bogus'},
projectId: 'bogus',
});
// Initialize client before mocking
client.initialize();
// Mock request
const request: protosTypes.google.cloud.bigquery.storage.v1beta1.ICreateReadSessionRequest = {};
request.tableReference = {};
Expand Down Expand Up @@ -165,6 +185,8 @@ describe('v1beta1.BigQueryStorageClient', () => {
credentials: {client_email: 'bogus', private_key: 'bogus'},
projectId: 'bogus',
});
// Initialize client before mocking
client.initialize();
// Mock request
const request: protosTypes.google.cloud.bigquery.storage.v1beta1.IBatchCreateReadSessionStreamsRequest = {};
request.session = {};
Expand All @@ -189,6 +211,8 @@ describe('v1beta1.BigQueryStorageClient', () => {
credentials: {client_email: 'bogus', private_key: 'bogus'},
projectId: 'bogus',
});
// Initialize client before mocking
client.initialize();
// Mock request
const request: protosTypes.google.cloud.bigquery.storage.v1beta1.IBatchCreateReadSessionStreamsRequest = {};
request.session = {};
Expand Down Expand Up @@ -218,6 +242,8 @@ describe('v1beta1.BigQueryStorageClient', () => {
credentials: {client_email: 'bogus', private_key: 'bogus'},
projectId: 'bogus',
});
// Initialize client before mocking
client.initialize();
// Mock request
const request: protosTypes.google.cloud.bigquery.storage.v1beta1.IFinalizeStreamRequest = {};
request.stream = {};
Expand All @@ -242,6 +268,8 @@ describe('v1beta1.BigQueryStorageClient', () => {
credentials: {client_email: 'bogus', private_key: 'bogus'},
projectId: 'bogus',
});
// Initialize client before mocking
client.initialize();
// Mock request
const request: protosTypes.google.cloud.bigquery.storage.v1beta1.IFinalizeStreamRequest = {};
request.stream = {};
Expand All @@ -268,6 +296,8 @@ describe('v1beta1.BigQueryStorageClient', () => {
credentials: {client_email: 'bogus', private_key: 'bogus'},
projectId: 'bogus',
});
// Initialize client before mocking
client.initialize();
// Mock request
const request: protosTypes.google.cloud.bigquery.storage.v1beta1.ISplitReadStreamRequest = {};
request.originalStream = {};
Expand All @@ -292,6 +322,8 @@ describe('v1beta1.BigQueryStorageClient', () => {
credentials: {client_email: 'bogus', private_key: 'bogus'},
projectId: 'bogus',
});
// Initialize client before mocking
client.initialize();
// Mock request
const request: protosTypes.google.cloud.bigquery.storage.v1beta1.ISplitReadStreamRequest = {};
request.originalStream = {};
Expand All @@ -318,6 +350,8 @@ describe('v1beta1.BigQueryStorageClient', () => {
credentials: {client_email: 'bogus', private_key: 'bogus'},
projectId: 'bogus',
});
// Initialize client before mocking
client.initialize();
// Mock request
const request: protosTypes.google.cloud.bigquery.storage.v1beta1.IReadRowsRequest = {};
request.readPosition = {};
Expand Down Expand Up @@ -346,6 +380,8 @@ describe('v1beta1.BigQueryStorageClient', () => {
credentials: {client_email: 'bogus', private_key: 'bogus'},
projectId: 'bogus',
});
// Initialize client before mocking
client.initialize();
// Mock request
const request: protosTypes.google.cloud.bigquery.storage.v1beta1.IReadRowsRequest = {};
request.readPosition = {};
Expand Down