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: add support for spanner client resource base routing #780

Closed
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
3b5c4de
feat: added method to get endPointUris and related changes
Dec 5, 2019
241fe62
fix: unit test cases was failing
Dec 6, 2019
d4d50b7
pass instanceId externally in each SpannerClient Request
Dec 6, 2019
87fd04a
feat: added flag to check weather resource based routing is enable or…
Dec 6, 2019
1ba9e16
move getInstanceEndPointUris to instance.ts file
Dec 9, 2019
2ac95bf
test: added unit test cases
Dec 10, 2019
f504666
fix: removed end point uris mapping chaching
Dec 11, 2019
cc5e72f
test:added more unit test cases
Dec 11, 2019
dfb8100
provided an option to enable resource based routing to user
Dec 13, 2019
9d4f4af
pass the instance id insted of formmatedName_ in each method
Dec 17, 2019
67f74af
fix: unit test cases
Dec 17, 2019
15f261d
fix: unit test cases
Dec 17, 2019
fe0e1a5
test:added system test
Dec 19, 2019
d46a13c
test:added unit test for instance permission
Dec 30, 2019
c4c12d2
fix:review changes
Dec 31, 2019
aae7311
refactor: simplify and clean up
Dec 31, 2019
0b7e83e
fix: reverse the resource based routing condition
Jan 1, 2020
59cdb4f
test: added unit test for multiple endpointUri
Jan 2, 2020
06fba33
Merge branch 'master' into resource-based-routing
Jan 10, 2020
600d5f1
fix:correct spell
Jan 10, 2020
2c99834
Merge branch 'master' into resource-based-routing
Jan 16, 2020
846cb78
refactor: replace getInstanceEndpointUris with getMetadata
Jan 16, 2020
1e83f37
Merge branch 'master' into resource-based-routing
Jan 22, 2020
57687ba
Merge branch 'master' into resource-based-routing
AVaksman Jan 23, 2020
eefc95d
Merge branch 'master' into resource-based-routing
Jan 24, 2020
4c2f6aa
fix:review changes
Jan 24, 2020
48085fb
fix: unit-test case fail issue
Jan 24, 2020
eb358f3
refactor: added enum to check the permission status
Jan 27, 2020
06dc72d
Merge branch 'master' into resource-based-routing
Jan 28, 2020
e5b02c5
merge:merge from master
Feb 6, 2020
710bc9a
fix: review changes
Feb 6, 2020
66eac38
Merge branch 'master' into resource-based-routing
Feb 10, 2020
a464043
test: added unit test and system-test cases
Feb 12, 2020
f3b976c
Merge branch 'master' into resource-based-routing
Feb 12, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 13 additions & 8 deletions src/index.ts
Expand Up @@ -35,7 +35,7 @@ import {SessionPool} from './session-pool';
import {Table} from './table';
import {PartitionedDml, Snapshot, Transaction} from './transaction';
import {GrpcClientOptions} from 'google-gax';
import {ChannelCredentials} from 'grpc';
import {ChannelCredentials, status} from 'grpc';
import {
createGcpApiConfig,
gcpCallInvocationTransformer,
Expand Down Expand Up @@ -793,7 +793,7 @@ class Spanner extends GrpcService {
}

/**
* get GAX client. This will retrive the end point uris for specific instance and cache the client accordingly.
* get GAX client. This will retrieve the end point uris for specific instance and cache the client accordingly.
*
* @private
*
Expand Down Expand Up @@ -830,10 +830,15 @@ class Spanner extends GrpcService {
},
(err, instance) => {
if (err) {
if (err.code === 7) {
process.emitWarning(
'spanner.instances.get permission must be added to use resource based routing.'
);
const PERMISSION_DENIED_MESSAGE = `The client library attempted to connect to
an endpoint closer to your Cloud Spanner data but was unable to
do so. The client library will fallback to the API endpoint given
in the client options, which may result in increased latency.
We recommend including the scope
https://www.googleapis.com/auth/spanner.admin
so that the client library can get an instance-specific endpoint and efficiently route requests.`;
if (err.code === status.PERMISSION_DENIED) {
process.emitWarning(PERMISSION_DENIED_MESSAGE);
this.setSpannerClient(clientName, config, this.options);
callback(null, this.clients_.get(clientName)!);
return;
Expand All @@ -855,11 +860,11 @@ class Spanner extends GrpcService {
}
}
/**
* cache the GAX client accordingly.
* Cache the GAX client accordingly.
*
* @private
*
* @param {string} clientName client name to cache.
* @param {string} clientName Client name to cache.
* @param {object} config Request config
* @param {object} options Spanner options
*/
Expand Down
26 changes: 16 additions & 10 deletions test/index.ts
Expand Up @@ -966,7 +966,7 @@ describe('Spanner', () => {
spanner.prepareGapicRequest_(CONFIG, assert.ifError);
});

it('should return an error from get instance endpointUris', done => {
it('should return an error from get instance endpointUris.', done => {
const error = new Error('Error.') as ServiceError;
const instanceId = 'instance-id';
spanner.options.enableResourceBasedRouting = true;
Expand All @@ -982,11 +982,15 @@ describe('Spanner', () => {
});
});

it('should continue if do not have permission for instance', done => {
it('should continue if a permission error is returned for the instance.', done => {
const PERMISSION_DENIED_MESSAGE = `The client library attempted to connect to
laljikanjareeya marked this conversation as resolved.
Show resolved Hide resolved
an endpoint closer to your Cloud Spanner data but was unable to
do so. The client library will fallback to the API endpoint given
in the client options, which may result in increased latency.
We recommend including the scope
https://www.googleapis.com/auth/spanner.admin
so that the client library can get an instance-specific endpoint and efficiently route requests.`;
sandbox.stub(process, 'emitWarning');
const expectedWarning =
'spanner.instances.get permission must be added to use resource based routing.';

const error = new Error('Error.') as ServiceError;
error.code = 7;
const instanceId = 'instance-id';
Expand All @@ -1000,13 +1004,15 @@ describe('Spanner', () => {
spanner.prepareGapicRequest_(CONFIG, err => {
assert.ifError(err);
assert.ok(
(process.emitWarning as sinon.SinonStub).calledWith(expectedWarning)
(process.emitWarning as sinon.SinonStub).calledWith(
PERMISSION_DENIED_MESSAGE
)
);
done();
});
});

it('should return an error if instanceId does not provided.', done => {
it('should return an error if instanceId is not provided.', done => {
spanner.options.enableResourceBasedRouting = true;

spanner.prepareGapicRequest_(CONFIG, err => {
Expand Down Expand Up @@ -1041,12 +1047,12 @@ describe('Spanner', () => {

it('should use user-specified endpoint when GetInstance response is empty.', done => {
const instanceId = 'instance-id';
const customeEndpoint = 'us-central1-spanner.googleapis.com';
const customEndpoint = 'us-central1-spanner.googleapis.com';
asAny(CONFIG).instanceId = instanceId;
spanner.options.enableResourceBasedRouting = true;

asAny(spanner).instance(instanceId).getMetadata = (options, callback) => {
asAny(spanner.options).apiEndpoint = customeEndpoint;
asAny(spanner.options).apiEndpoint = customEndpoint;
callback!(null, {endpointUris: []});
};

Expand All @@ -1063,7 +1069,7 @@ describe('Spanner', () => {
spanner.prepareGapicRequest_(CONFIG, assert.ifError);
});

it('should override the first endpoint while multiple endpointUri available.', done => {
it('should override the first endpoint while multiple endpointUris are available.', done => {
const GOOGLE_CLOUD_ENABLE_RESOURCE_BASED_ROUTING =
process.env.GOOGLE_CLOUD_ENABLE_RESOURCE_BASED_ROUTING;
process.env.GOOGLE_CLOUD_ENABLE_RESOURCE_BASED_ROUTING = 'true';
Expand Down
3 changes: 2 additions & 1 deletion test/spanner.ts
Expand Up @@ -27,7 +27,7 @@ import * as sinon from 'sinon';
import {google} from '../protos/protos';
import {types} from '../src/session';
import {ExecuteSqlRequest, RunResponse} from '../src/transaction';
import {PartialResultStream, Row} from '../src/partial-result-stream';
import {Row} from '../src/partial-result-stream';
import {
SessionLeakError,
SessionPoolExhaustedError,
Expand Down Expand Up @@ -97,6 +97,7 @@ describe('Spanner with mock server', () => {
servicePath: 'localhost',
port,
sslCreds: grpc.credentials.createInsecure(),
enableResourceBasedRouting: false, //diabled resource based routing
});
// Gets a reference to a Cloud Spanner instance and database
instance = spanner.instance('instance');
Expand Down