Feature: Server-side request interceptor (#749)#963
Feature: Server-side request interceptor (#749)#963sergeybykov merged 1 commit intodotnet:masterfrom
Conversation
|
You don't need XML file for the test. We have programmable API for providers and there is a virtual base method in the unit test class that can be overwritten to tweak the config object . |
|
Thumbs up. |
|
Many thanks, @gabikliot. I'll push an update in a minute. |
d26b8ef to
c2b9eb0
Compare
|
Awesome! Very simple implementation and pretty much exactly what I'd like to use for pre-method call setup (in my case, extracting the User ID from the RequestContext, then setting up the Thread.CurrentPrincipal, then invoking the method). One suggestion for my use case (only me?) would be for this interceptor to return an IDisposable, which is disposed of when the call completes, so we can dismantle any context (eg, set Thread.CurrentPrincipal back to NULL, by returning a class that will do that upon disposal): // From
public Action<InvokeMethodRequest, IGrain> PreInvokeCallback
// To
public Func<InvokeMethodRequest, IGrain, IDisposable> PreInvokeCallbackThen in the calling code: // From
SiloProviderRuntime.Instance.CallPreInvokeCallback(request, target);
resultObject = await invoker.Invoke(target, request.InterfaceId, request.MethodId, request.Arguments);
// To
using (SiloProviderRuntime.Instance.CallPreInvokeCallback(request, target))
resultObject = await invoker.Invoke(target, request.InterfaceId, request.MethodId, request.Arguments);Thoughts? |
|
@Plasma I don't understand why would you need a Disposable here? If interception will be implemented in a way it is implemented in every other project out there, specifically as decorator pattern, where you control invocation - you will have an easy way to understand when the call is finished. But I suspect it want happen due to blocking from a core team, as they're scared that we'll abuse it (for the greater go0d). Poor puppy's are we ... 😄 |
|
@Plasma Wouldn't a symmetric post-invoke callback be a cleaner solution for what you need than IDosposable? |
|
@yevhen @sergeybykov Yep either of those two options sound great to me. |
c2b9eb0 to
3001fa7
Compare
|
@sergeybykov forget about IDisposable. That solution was a obvious no-go for anyone. We are not even discussing per-type interceptor. What we are really discussing is 2 different interception approaches:
The first model has a number of clear advantages such as:
The second model:
Regarding second model: been there, done that. It was incredibly frustrating experience. Anyone who tried to do anything meaningful with ASP.NET WebForms Pre/Post model know what I'm talking about. If you're against that virtual method - fine. I do care only about approach. If it will be pipelining implemented only as global callback - it's fine. I'll be able to add per-type interception in my own sandbox then. But if it will be a pre/post callback - it is the same as having no feature for me. And let's remove personalities from this discussion. I don't really care what @yevhen or @Plasma need or think is enough for his particular situation. But I do care about other people looking at that and thinking: Holy crap what they were smoking when designed that feature? The end. |
|
The second model:
|
But what if there are valid reason not to throw but still cancel?
no, it's not. Due to interleaving (reentrant) grains, PostInvoke will not correlate with PreInvoke. Users will need to correlate themselves.
Sure. The correlation problem described above, is exactly due to lack of composition. Try to do this with Pre/Post model: PerformLogging(
CollectStatistics(MessageCategory.Command,
PublishEvents(Log, publisher,
RetryOnConcurrencyConflicts(retryOnConcurrency, Log,
RetryOnDuplicates(retryOnDuplicates, Log,
HandleIdempotency(Log,
WithinDbTransaction(store, tx =>
request => handler(request)
)))))))(x)); |
|
Good point about reentrant grains. OK, I remove my objection to pipelining interceptors. The need to manually correlate the pre and post for reentrant calls is a problem. |
|
Thumbs up!
|
|
Went to a run and thought more about it. Still did not see a single example where a value need to be returned from the pre decorator without invoking the actual logic ("cancelation and not throwing" scenario). Caching I think is too application specific, and is also different per method and not per grain type, so better done inside the grain logic itself. |
|
Using Having request interceptors as described allows for a much cleaner design: it gives consumers the option of accessing the grain directly. They can access/modify private members or use the request scoping of their IoC container EDIT: I rather we do not merge this until the design in #965 is settled. |
|
Note to self: |
|
@ReubenBond Can you rebase this one? Will you have time to complete it? If not, we can try to do that. |
|
@sergeybykov when comparing this PR to #965 (comment) - does #965 adequately address server side interception? Maybe I'm misreading it but does the grain intercept code in #965 happen on the server side (thus it can access memory / logical state on the silo and do whatever it wants before the code actually executes)? If so, I personally don't need this PR anymore. |
|
@Plasma yes, #965 is for server-side grain interception, too. It does not allow for a single global interceptor, though. @sergeybykov I've rebased privately, but this PR is not ready to prime-time yet. |
501dd6d to
cf31d53
Compare
There was a problem hiding this comment.
This class was shifted from another file & should not be functionally different to how it was with #965
cf31d53 to
fd0cf75
Compare
|
Rebased & squashed 😄 Please critique & consider merging. |
src/Orleans/Core/GrainClient.cs
Outdated
There was a problem hiding this comment.
These params don't match the callback definition.
fd0cf75 to
6f9ef20
Compare
There was a problem hiding this comment.
Since InvokeInterceptor is a delegate, if I add more than one interceptor, they will be called in parallel, not as a pipeline? And each interceptor will invoke the grain via invoker?
6f9ef20 to
c0a886e
Compare
Feature: Server-side request interceptor (#749)
|
Thank you, @ReubenBond for completing it! |
Based on the discussion in #749.