dotnet / orleans

Cloud Native application framework for .NET
https://docs.microsoft.com/dotnet/orleans
MIT License
10.07k stars 2.03k forks source link

Is there a way to intercept outgoing calls with the caller grain context instead of callee? #6313

Closed rvplauborg closed 4 years ago

rvplauborg commented 4 years ago

Hi,

To me the outgoing call filter was a bit counter intuitive, as I would have expected the context to be that of the caller grain, meaning that I could call methods on that grain and then in an incoming filter call methods on the callee grain. But both filter types' context is that of the callee grain. So I was wondering, if there is a way at all to intercept an outgoing call from a caller grain, where the context belongs to that caller grain and not the callee?

This might be related to #2139

Best regards

ReubenBond commented 4 years ago

I'm not sure I understand. The execution flow is like this:

Calling Client/Grain ---> IOutgoingGrainCallFilter on caller context ---> network, etc ---> IIncomingGrainCallFilter on callee context ---> Target Grain

The outgoing call filter is executed in the context of whoever is making the call. An incoming call filter is executed in the context of whoever is receiving the call.

rvplauborg commented 4 years ago

We have an IOutgoingGrainCallFilter, but context.Grain in the Invoke method gives us the grain being invoked, not the invoker - same as it does on an incoming filter. It also states this in the documentation https://dotnet.github.io/orleans/Documentation/grains/interceptors.html#outgoing-call-filters:

public interface IOutgoingGrainCallContext
{
    /// <summary>
    /// Gets the grain **being invoked.**
    /// </summary>
    IAddressable Grain { get; }
...

It also states in the same section:

The MethodInfo of the interface method being called can be accessed using the InterfaceMethod property.

So while the execution flow is correct, it seems we have the callee grain context in both outgoing and incoming filters, and never the caller grain context. I hope that cleared up what I meant, if not please let me know.

Basically what I am asking is if it is possible to do context.Grain and get the caller grain and not the callee grain.

ReubenBond commented 4 years ago

Got it. Yes, context.Grain is a reference (GrainReference) of the grain being invoked. The call doesn't necessarily originate from a grain. For example, it may originate from an external client.

There is currently no exposed method for getting the Grain instance which a call originates from (assuming it originates from a grain).

What you're asking for is reasonable, however. I think it's something we can consider for 4.0. For the time being, you could use an AsyncLocal to hold the currently executing grain and access that from your outgoing call filter. You could set that value during the incoming call filter (which gives you a grain instance, not just a grain reference) so that it's hopefully available when needed.

rvplauborg commented 4 years ago

Thank you for clearing that up. We have mitigated our issue, but for me it is a bit unclear what different use cases outgoing vs. ingoing support - I am having a hard time separating the use cases for the two. I think it would be a powerful feature to have the caller grain available in a filter, so I am excited to see if it makes its way into the framework in the future.

Again thank you for the very informative replies!