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: spanner emulator support #4915

Merged
merged 21 commits into from
May 28, 2020

Conversation

skuruppu
Copy link
Contributor

@skuruppu skuruppu commented Apr 29, 2020

  • Allows users to set EmulatorDetection through SpannerConnectionStringBuilder.
  • Configures integration tests with EmulatorDetection.EmulatorOrProduction.

@skuruppu skuruppu added the api: spanner Issues related to the Spanner API. label Apr 29, 2020
@googlebot googlebot added the cla: yes This human has signed the Contributor License Agreement. label Apr 29, 2020
@skuruppu skuruppu requested a review from jskeet April 29, 2020 05:09
@skuruppu
Copy link
Contributor Author

Currently this only addresses the second dot point of the comment. I am still figuring out how to address the third point.

@jskeet I just wanted some quick feedback from you on whether I'm on the right track :) No need to do a detailed review for now.

Copy link
Collaborator

@jskeet jskeet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comments will apply for all three - but yes, this looks it's the the right starting point. Once this is in place, I'm hoping the Spanner.Data integration should be straightforward.

@skuruppu skuruppu marked this pull request as ready for review May 1, 2020 02:35
@skuruppu
Copy link
Contributor Author

skuruppu commented May 1, 2020

@jskeet this is now ready for review. I ran the ITs and they ran for the most part:

Total tests: 167
Passed: 92
Failed: 74
Skipped: 1

I will go through the failed tests to figure out which ones need to be skipped (due to the emulator not supporting all features that the production backend supports). This will need to be done in a separate PR. If there's anything that can be fixed in terms of the setup, I will do so in this PR.

Copy link
Collaborator

@jskeet jskeet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest we split this PR in half: let's get the easy bits (the three underlying API clients) done first, then look at how we configure it from Spanner.Data as a separate PR.

But fundamentally I'd really like SpannerConnectionStringBuilder and SpannerClientCreationOptions to do the bulk of the work here.

@@ -313,7 +323,8 @@ private static async Task<SpannerClient> CreateClientAsync(SpannerClientCreation
return new SpannerClientBuilder
{
CallInvoker = callInvoker,
Settings = spannerSettings
Settings = spannerSettings,
EmulatorDetection = emulatorDetection
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting a call invoker and emulator detection would be an odd thing to do. (I'm slightly surprised we don't prohibit it.)
If we do the work in SpannerClientCreationOptions (which may mean some code duplication, unfortunately - let's see what we can do) the endpoint and credentials will already be set correctly, so we shouldn't need to make any changes here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see, so we shouldn't rely on the automated emulator detection for the data client. We should only do that for the admin clients. So we'll manually read the env var and set the endpoint and credentials. Is the worry that it would confuse users because they would set an endpoint and credentials but we'd be using a different parameters for the actual connection?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not a matter of "not relying" on the automated emulation code - it's not that we don't trust it. It's a matter of making it fit in well with the rest of the infrastructure.
I'd like to investigate how to do this without code duplication though - for example, it may be possible to add a public member to SpannerClientBuilder to say "please let me know how you would be configured for emulation" (effectively like the current partial method does) and then use the endpoint and credentials from that.

I think our aim should be for the behavior to be consistent between "using SpannerClientBuilder directly" and "using SpannerConnectionStringBuilder directly" in terms of the connection.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've made the minimal amount of changes to get this working. But I'm still not updating the endpoint and credentials in the connection string to reflect what is actually being connected to. I think this is where your comment regarding updating the SpannerClientBuilder comes in.

The other issue that I want to solve is that if the connection string has EmulatorDetection then users shouldn't be asked to specify credentials. I'll also work on trying to bypass this check.

@skuruppu
Copy link
Contributor Author

skuruppu commented May 5, 2020

Thanks @jskeet. I agree about doing this as two separate PRs. To preserve the discussion, I may leave this PR as is to continue the work on setting the connection properties. I'll cherry-pick the builders into a separate PR.

@jskeet
Copy link
Collaborator

jskeet commented May 5, 2020

I've merged #4928 now, so it's probably worth rebasing this PR, unless you'd prefer to start a new one.

@skuruppu skuruppu marked this pull request as draft May 7, 2020 09:57
@skuruppu skuruppu marked this pull request as ready for review May 13, 2020 05:06
@skuruppu skuruppu requested a review from a team as a code owner May 13, 2020 05:06
@jskeet
Copy link
Collaborator

jskeet commented May 13, 2020

I'll get to this when I can, but it may go into next week I'm afraid.

@skuruppu
Copy link
Contributor Author

No worries @jskeet. I'm also sporadically working on it when I find bits of time here and there.

Copy link
Collaborator

@jskeet jskeet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is moving in the right direction, but I think we probably need to move the CallInvoker creation from SessionPoolManager into SpannerClientCreationOptions. We may need to add something to SpannerClientBuilder to make it easier to say "What endpoint and credentials would you use for this?" without actually performing the build afterwards.

It's tricky for me to speculate on exactly what's required without basically doing it myself, unfortunately. Let me know how you'd like us to proceed.

@skuruppu
Copy link
Contributor Author

This is what I came up with for now e98b470. I don't think you need to move the CallInvoker to SpannerClientCreationOptions, as long as the endpoint and credentials can be correctly extracted from that class.

My proposed change to SpannerClientBuilder is a bit of a mess since there's no nice way to extract the endpoint and credentials without attempting to build an instance of the class. For now I'm reading the env var manually. But if there was a static version of GetEmulatorEnvironment that also accepts an EmulatorDetection argument, then it might be cleaner.

Sorry, I know the back-and-forth is taking a bit of time. I'm more than happy for you to take a crack at this but I know you have a lot more stuff going on so I want to help as much as possible.

@jskeet
Copy link
Collaborator

jskeet commented May 20, 2020

Building an instance of SpannerClientBuilder is the way to go - we want to get the same exact behaviour as if we were specifying the emulator detection in the builder.

I would suggest just making MaybeCreateEmulatorClientBuilder public - then you can use that in SessionPoolManager. If it returns a non-null value, use the endpoint and credentials from that.

@skuruppu
Copy link
Contributor Author

PTAL @jskeet. I made all the discussed changes.

@jskeet
Copy link
Collaborator

jskeet commented May 26, 2020

Will have a look when I get a chance, but it may well be quite late in the week.

Copy link
Collaborator

@jskeet jskeet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting a lot closer - but the session pool options bother me. Do you want me to see if I can figure out a way that we can make the options "just work"?

};
var emulatorBuilder = clientBuilder.MaybeCreateEmulatorClientBuilder();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder whether this should be in the production code, if everyone will always need to do that.
Do we know whether this is a long-term restriction?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, the changes in this file (beyond just setting EmulatorDetection) feel like they're a symptom of us not doing quite enough to "just make it work".

ConnectionString = databaseBuilder.ConnectionString;
DatabaseName = databaseBuilder.DatabaseName;
Builder = builder.WithDatabase(SpannerDatabase);
Builder.EmulatorDetection = emulatorDetection;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't need to set the EmulatorDetection again, should we?

@@ -116,6 +143,6 @@ private static string GetEnvironmentVariableOrDefault(string name, string defaul
return string.IsNullOrEmpty(value) ? defaultValue : value;
}

public SpannerConnection GetConnection() => new SpannerConnection(ConnectionString);
public SpannerConnection GetConnection() => new SpannerConnection(Builder);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this change required? I'd expect the connection string to be fine.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or is this because we've set the SessionPoolManager because of the options? It feels like a lot of this change could go away if we didn't need to set the options explicitly.

@skuruppu
Copy link
Contributor Author

skuruppu commented May 28, 2020

I addressed most of the changes except for the ones in https://github.com/googleapis/google-cloud-dotnet/pull/4915/files#diff-450b4cc43d8fb620f621d63b7de37a31 relating to the session pool.

For context, the changes to that file came out of #4970 when I was trying to run the existing ITs against the emulator. To be honest, I haven't quite gotten the whole thing to work yet even with that change.

My preference would be to revert the changes to that file and work on it separately. The highest priority is to add the emulator support to the client since there is a customer that's keen to try this out in C#.

Getting the ITs to work is a bonus so that we can report emulator issues to the dev team and perhaps have a presubmit that runs the ITs against the emulator. But this will require a bunch of work from my side and from the emulator team to fix some of the failing tests.

@jskeet I would be happy for you to try out a fix for the session pool issue. I'm not familiar with it enough to know what to change. But only if you have time. Otherwise, I'll work on it until I figure it out.

I don't know if the emulator team is planning to fix the concurrent transaction issue before GA. I will check with them and get back to you.

Let me know if you're ok with me reverting changes to that file.

Copy link
Collaborator

@jskeet jskeet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that we should revert the integration test change - and the rest now looks good to me. I can try the integration test piece early next week, I expect, but we could get this in before then and do a beta release. The customer would need to configure the session pool options themselves in that beta release, but we can hope to either do it for them in a later release, or not need to do it at all if the emulator changes.

@skuruppu
Copy link
Contributor Author

All done, thanks for the review feedback @jskeet.

Copy link
Collaborator

@jskeet jskeet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks - will squash and merge, then look into the SessionPoolOptions aspect.

@jskeet jskeet merged commit a4455b9 into googleapis:master May 28, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api: spanner Issues related to the Spanner API. cla: yes This human has signed the Contributor License Agreement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants