-
Notifications
You must be signed in to change notification settings - Fork 25
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
New Syntax #49
New Syntax #49
Conversation
I was left wondering, and I think that we need to change the constructor's signature of monkey policies (latency, fault, etc) as well (or add another overload to continue supporting the old syntax as is), to inject the options object rather than the delegates separately. For example with the Like this:
|
Hey @vany0114 . Thank you so much for getting us into action with this syntax! It's great to be doing this for Simmy, also because we are hopefully thinking to do similar with Polly. Thank you also for the super clear questions/explanations - very helpful. I love the new I had an idea that maybe we could use method-chaining, to make a builder syntax, and separate more the individual items to be configured. To explore this, it seemed easier to make an example than give long-description, so I made a sketch in this branch. It builds on your commit (because of the great stuff already in there), so it is also easy to see the differences in the commit. What do you think? Configuring a policy ends up looking something like this: For a simple case (more constants than delegates): var policy = MonkeyPolicy.InjectBehaviourAsync(with =>
with.Behaviour(() =>
{
injectedBehaviourExecuted = true;
return Task.CompletedTask;
})
.InjectionRate(0.6)
.Enabled(false)
); For a more complex case (delegates): var policy = MonkeyPolicy.InjectBehaviourAsync(with =>
with.Behaviour((context, ct) => { ... })
.InjectionRate((context, ct) => GetInjectionRate(context, ct)) // or just .InjectionRate(GetInjectionRate)
.EnabledWhen((context, ct) => GetEnabled(context, ct)) // or just .EnabledWhen(GetEnabled)
); Or mixing complex and simple: var policy = MonkeyPolicy.InjectBehaviourAsync(with =>
with.Behaviour(() => { ... })
.InjectionRate((context, ct) => GetInjectionRate(context, ct))
.Enabled()
); Thoughts about this sketch? |
One observation/question about the sketch ^: I made all the properties on the For Simmy so far, it looks like that would probably make sense. But it doesn't have to be this way. Theoretically, if a policy has some properties which are constant primitives (eg number of retries; duration of circuit-breaking), it would be possible to leave those with public setters (so that they could be eg loaded with standard .NET Core Options/Configuration patterns) (x-ref App-vNext/Polly#143), with the other properties I do not have a strong view at this point whether such a mixture would be a good idea; it might lead to overloads like: var policy = Policy
.Handle<FooException>()
.CircuitBreaker(circuitBreakerOptions, with =>
with.OnBreak(() => { ... })
);
// Or maybe:
var policy = Policy
.Handle<FooException>()
.CircuitBreaker(configure =>
configure.FromOptions(circuitBreakerOptions)
.OnBreak(() => { ... })
); Maybe this mixture would be more a question for later; but mentioning it because it was an intentional change in the code sketch to make the properties |
@vany0114 Re this comment: Yes, agree with all! 👍
yes, much better. Re:
Yes, we could mark it (For Polly we would have to think more carefully about supporting old syntax (though we would still freeze it). Maybe we would use a 'compatibility pack' - I have some ideas.) |
Hey @reisenberger. I really like how the syntax looks using method-chaining, I think is easier to use not to mention it's more intuitive. Thanks for bringing such a cool idea. Regarding mixing And I agree that we can remove the old syntax since as you said, Simmy is still pretty young and we're not even in a 1.X version. Thanks again for taking the time reviewing this PR and for the cool ideas you suggest (as usual)! |
Sounds good @vany0114 ! Thanks for so taking ownership of this and pushing Simmy along so awesomely! Please let me know when/if I can be useful to review a next stage together (but sounds like we are on a great path!). (I didn't look at latest commit yet - just shout when you want me to circle back round and look) Again: thanks! 💯 |
@reisenberger I think I've finished with this PR, it's a huge one, but all the work comes down to this:
Also, I took advantage to solve #15. I've created this guy to ensure the injection rate not only from the engine at execution time but also at configuration time, and I added some unit tests around that. Regarding the old syntax, I ended up keeping it just to be kinda kind with the users 😅 I mean, I think it's nice to warn them about that first, before to break their code, but I think for version 1.0 (hopefully we'll be able to make it this year) we can get rid of all the deprecated code, what do you think? Thanks in advance for your time reviewing PR's 👀 and also to bringing cool ideas, I really appreciate it! Note: Once we finish with this PR, I'll create another one to update the documentation. |
@reisenberger BTW I've created this variation (actually just using a different name) into the Basically to do this:
Not sure about that, I was thinking it might be more descriptive for the user, what do you think? |
@vany0114 Looks great to me! 👍 💯 Two small things we could clean-up (if you agree?):
(I think these were both things in the earlier sketch, sorry for raising them now!) |
@vany0114 Re your great question around "inject result" language instead of "inject fault": great question, because maybe the user would like sometimes to inject something which isn't strictly a fault, maybe they want to inject a 301 redirect (or a 200OK even, in a unit test). So maybe our API language should be more neutral than "fault"? (but offer a wording with "fault", for the common case). I was also wondering about the near-collision between:
There is enough difference that the compiler can distinguish, but it could still be confusing for users. (I could see a user writing
as well as:
What do you think? Or any other suggestion? Although this ^ is an API change (InjectFault -> InjectResult), now is the time to do it, we are only at 0.X semver, so it is understood we can change this now to get it right before 1.0 |
Yeah, agree with both of them. You're right, the fact to have an extra using might be annoying, good catch! |
No problem, it was my bad originally! I checked various Microsoft repos and it's certainly standard not to have an |
@reisenberger Also agree with changing the API wording. I'll work thru that. And thanks for taking the time to review it in such a thorough way! 👍 🥇 |
@reisenberger what do you think if we keep the |
My suggestion would be removing the For background: With Polly, we had feedback about that being unexpected for the static-method Policy syntax, ie the fact that classes like this live in folder I had done that because I wanted to keep everything about one policy together (in folder
(We don't necessarily have to solve the decision about location of syntax partial classes of |
I thought we could keep the Said that, I'll remove the |
Hi @reisenberger I just finished with the suggestions, I also took advantage to implement #16, I just renamed the |
@vany0114 This is great! The only thing I spotted: I had thought that we should move the I experimented with doing that (to see if it caused any other problems), and noticed that, if a consuming class (a test class in our case) didn't have the appropriate
For example, this occurred where This is not very satisfactory, because it risks letting users fall into a pit-of-failure (not pit-of-success), because it is quite likely that users copy code-snippets into their code without copying the accompanying using statements. This is my bad. It looks like the original sketch was 'too clever' (has this risk) if naming the internal property and the extension method the same thing. So TL;DR I made a commit to rename relevant internal properties to Then I noticed some classes/filenames where we still had 'Fault' and could say 'Outcome'; I pushed a commit to rename those. Apologies for jumping in with commits, it looked as if some of my previous suggestions might have caused some problems, so I cleaned up after myself this time 😉 What do you think? If you are happy with this branch, we could PR that onto your PR here, and then merge this #49? Or can you spot anything else? It's great that we have done all the work on this, because it's a great model for Polly too! 👍 |
@reisenberger those are really good catches, thanks for fixing them!
Apologies for that, I thought I had done with it but I was far away 😅
Yeah, totally agree, let's do it! |
Maybe when we finally merge this to |
Yeah, definitely. Also, I think I have to rename de branch, at the beginning I thought it was going to be just for #48 and maybe for #46 that's why I named What do you think? |
Yes, feel free to rename it if you want! (Though after it is merged to |
…amespace Namespace, filename and property-name cleanups
Hi @reisenberger,
This is the very beginning of the new syntax model for Simmy (WIP), just wanted to get feedback early with this PR.
Options objects
So, the idea is that every monkey policy has its own options objects, like this:
Basic options
Applies for sync and async executions and the idea is to give to the user another overload to set a monkey policy easily using primitives rather than delegates. (when user doesn't care about cancellation, context, etc)
Syntax
Every monkey policy has its own option syntax, like this:
Where every syntax offers two overloads, one with its own options objects and another one with the default ones. That way, I think, we're covering all the syntax that we're currently offering thru the old syntax.
Examples:
Let me know your thoughts, please.
Note: I think after this change, we should mark as obsolete the old syntax overloads, right?