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

Overhaul of the execution pipeline #2918

Merged
merged 11 commits into from
Jan 24, 2024
Merged

Overhaul of the execution pipeline #2918

merged 11 commits into from
Jan 24, 2024

Conversation

jeremydmiller
Copy link
Member

  • New "auto-closing connection lifetime" by default
  • Async daemon is using NpgsqlBatch
  • Ripped out IRetryPolicy
  • Getting the operation processing ready for effective retries

* New "auto-closing connection lifetime" by default
* Async daemon is using NpgsqlBatch
* Ripped out IRetryPolicy
* Getting the operation processing ready for effective retries
@jeremydmiller jeremydmiller marked this pull request as ready for review January 24, 2024 00:25
<!-- endSnippet -->

Also you could use the fantastic [Polly](https://www.nuget.org/packages/polly) library to easily build more resilient and expressive retry policies by implementing `IRetryPolicy`.
Marten's previous, homegrown `IRetryPolicy` mechanism was completely replaced by [Polly](https://www.nuget.org/packages/polly) in Marten V7.
Copy link
Collaborator

Choose a reason for hiding this comment

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

SUGGESTION: It'd be good to provide some samples on how to plug Polly policies to Marten.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I agree. Like I told y'all in Discord, I hadn't made any effort to document anything yet.

@oskardudycz
Copy link
Collaborator

The PR scope and type of changes is big, so pardon me if I didn't get it right. I assume that the only way to set a reusing connection now is to either:

  • have it managed by Marten and use the connection from the document session in external calls,
  • have it injected through SessionOptions with the transaction.

Is it correct?

I'd love to get rid of those injections with the Connection and lazy-loaded stuff, but I'm not sure if that won't be too big a change for some of the users and would make them stay on the older versions. On the other hand, that's more of a guess for now on how many people are using such a way.

We still need to do benchmarks if there's no performance degradation, as the opening connection can be quite costly, especially around the non-pooled usage.

I think those changes are in the right direction, but it has to be precisely documented, as the auto-closing introduces more magic and an implicit understanding of the stuff. My main fright is that this can be pretty nasty for the existing users, as such bugs may happen only in specific usage (so be seen as non-deterministic). Maybe we could introduce some "v6-compatibility mode" that'd set it up as close as possible to previous behaviour?

public int Execute(NpgsqlCommand cmd)
{
Logger.OnBeforeExecute(cmd);
using var conn = _database.CreateConnection();
Copy link
Collaborator

Choose a reason for hiding this comment

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

SUGGESTION: Maybe we should put a circuit breaker for the default exception when the server is down. Doing reconnections may flood it and not allow it to start when multiple requests or instances will try to do retries.

Copy link
Member Author

Choose a reason for hiding this comment

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

I was going to agree with you, but changed my mind after thinking about it more. I'd recommend folks put the circuit breaker higher up in the stack. If folks were using Wolverine for example, I'd say you put the circuit breaker on the message processing level and do that with Wolverine itself.

Maybe an example in the docs though so you can opt into that yourself w/ some copy/paste code.

@jeremydmiller
Copy link
Member Author

@oskardudycz:

"I assume that the only way to set a reusing connection now is to either:" -- not quite. If you call IDocumentSession.BeginTransaction() or use the IDocumentSession.Connection in a raw way, it reverts to the old "sticky" connection handling.

"I'd love to get rid of those injections with the Connection and lazy-loaded stuff, but I'm not sure if that won't be too big a change for some of the users and would make them stay on the older versions. On the other hand, that's more of a guess for now on how many people are using such a way."

  • Ditto from me. I'd say to leave those alone and maybe encourage folks to move away from that over time in docs. One thing I wimped out on was changing the ambient transaction behavior. If you opt into ambient "EnlistInTransaction" behavior, it's still the old sticky connection code. And you do have to keep that connection pushing behavior to enable folks who want to use EF Core or Dapper and Marten in the same native db transaction.

"We still need to do benchmarks if there's no performance degradation, as the opening connection can be quite costly, especially around the non-pooled usage."

Of course. I was working last night on battery power (and a cold). I'll run the benchmarks today and report back. I'm not buying that there's going to be any "performance degradation". The connection pooling is all underneath Npgsql itself, and I don't think this change will have any significant impact on performance due to connection pooling. Besides, even under the old model we didn't open the connection until we had to. Under heavy load, I'd expect it to be the opposite as Npgsql won't have to use so many connections. And also, look much closer at the change in behavior around Polly w/ the static lambdas vs how we were using IRetryPolicy before. What we were doing with IRetryPolicy was pretty gross in terms of object allocations. I would expect the new model to be faster.

"I think those changes are in the right direction, but it has to be precisely documented, as the auto-closing introduces more magic and an implicit understanding of the stuff. My main fright is that this can be pretty nasty for the existing users, as such bugs may happen only in specific usage (so be seen as non-deterministic). Maybe we could introduce some "v6-compatibility mode" that'd set it up as close as possible to previous behaviour?"

I'd thought about the v6-compatible switch. That's relatively easy to do, but I'd do that w/ a follow up PR. I think that's a good idea. The old connection lifetime mechanics are essentially still there, it's a state pattern switch here

@jeremydmiller
Copy link
Member Author

@oskardudycz Another problem for a day soon I guess, the NpgsqlDataSource mechanics do not work with Marten whatsoever. There's some differences in connection behavior with using the data source. You can't hide NpgsqlDataSource behind an IConnectionFactory like we do.

So we're still dead in the water w/ Project Aspire and using an underlying NpgsqlDataSource. I think maybe we could beat that after the IConnectionLifetime changes in this PR, but previously, that prevents Marten from releasing connections somehow and kaboom.

@jeremydmiller jeremydmiller merged commit 690861a into master Jan 24, 2024
11 checks passed
@jeremydmiller jeremydmiller deleted the polly branch January 24, 2024 23:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants