orleans icon indicating copy to clipboard operation
orleans copied to clipboard

Unable to invoke GrainService from Filter

Open galvesribeiro opened this issue 4 years ago • 7 comments

Hello!

From a a IIncomingGrainCallFilter implementation, I'm able a IGrainServiceClient implementation.

However, if I try to invoke any methods on the client I get this NRE:

Exception has occurred: CLR/Orleans.Runtime.OrleansLifecycleCanceledException
An exception of type 'Orleans.Runtime.OrleansLifecycleCanceledException' occurred in System.Private.CoreLib.dll but was not handled in user code: 'Lifecycle start canceled due to errors at stage 8000'
 Inner exceptions found, see $exception in variables window for more details.
 Innermost exception 	 System.NullReferenceException : Object reference not set to an instance of an object.
   at Orleans.Runtime.Services.GrainServiceClient`1.MapGrainReferenceToSiloRing(GrainReference grainRef)
   at Orleans.Runtime.Services.GrainServiceClient`1.get_GrainService()
   at Orleans.Dashboard.AgentServiceClient.ReportProfile() in /Users/guto/dev/repos/OrleansContrib/Orleans.Dashboard/src/Orleans.Dashboard.Agent/AgentServiceClient.cs:line 13
   at Orleans.Dashboard.ProfileGrainInvocationFilter.<Invoke>d__3.MoveNext() in /Users/guto/dev/repos/OrleansContrib/Orleans.Dashboard/src/Orleans.Dashboard.Agent/Profiling/ProfileGrainInvocationFilter.cs:line 22
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Orleans.Runtime.GrainMethodInvoker.<Invoke>d__21.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Orleans.Runtime.InsideRuntimeClient.<Invoke>d__62.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at Orleans.OrleansTaskExtentions.<<ToTypedTask>g__ConvertAsync|4_0>d`1.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Orleans.OrleansTaskExtentions.<WithTimeout>d__19`1.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at Orleans.Runtime.MembershipService.SystemTargetBasedMembershipTable.<WaitForTableGrainToInit>d__6.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Orleans.Runtime.MembershipService.SystemTargetBasedMembershipTable.<GetMembershipTable>d__5.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Orleans.Runtime.MembershipService.SystemTargetBasedMembershipTable.<InitializeMembershipTable>d__4.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Orleans.Runtime.MembershipService.MembershipOracle.<Start>d__32.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Orleans.Runtime.Scheduler.AsyncClosureWorkItem.<Execute>d__8.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Orleans.OrleansTaskExtentions.<WithTimeout>d__18.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Orleans.Runtime.Silo.<>c__DisplayClass72_0.<<OnRuntimeGrainServicesStart>g__StartMembershipOracle|1>d.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Orleans.Runtime.Silo.<StartAsyncTaskWithPerfAnalysis>d__70.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Orleans.Runtime.Silo.<OnRuntimeGrainServicesStart>d__72.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Orleans.Runtime.SiloLifecycleSubject.MonitoredObserver.<OnStart>d__9.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Orleans.LifecycleSubject.<WrapExecution>d__10.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at Orleans.LifecycleSubject.<OnStart>d__5.MoveNext()

Can someone tell me if it is supported to invoke grain services from a filter? I know we can invoke grains but idk about grain services.

Thanks!

galvesribeiro avatar Aug 02 '19 05:08 galvesribeiro

With 3.0 I'm getting NRE from MapGrainReferenceToSiloRing for any reference to GrainService in the client class. No filter involved. You don't even have to call a method, just checking whether GrainService is null trips the exception, so it's apparently some init process in the property getter. I set up a bare-minimum example:

public interface IEchoGrainService : IGrainService
{
    Task<string> Echo(string input);
}

public class EchoGrainService : GrainService, IEchoGrainService
{
    public EchoGrainService(IConfiguration config, IGrainIdentity id, Silo silo, ILoggerFactory loggerFactory)
        : base(id, silo, loggerFactory) { }

    public Task<string> Echo(string input)
        => Task.FromResult(input);
}

public interface IEchoClient : IGrainServiceClient<IEchoGrainService>, IEchoGrainService
{ }

public class EchoClient : GrainServiceClient<IEchoGrainService>, IEchoClient
{
    public EchoClient(IServiceProvider services)
        : base(services) { }

    public Task<string> Echo(string input)
        => GrainService.Echo(input);  // throws NRE
        // => $"null? {GrainService is null}";  // also throws NRE
}

Silo setup:

host.UseOrleans((hostContext, siloBuilder) =>
{
    siloBuilder    // omitted cluster setup etc.
    .ConfigureApplicationParts(parts =>
    {
        parts.AddApplicationPart(typeof(EchoGrainService).Assembly).WithReferences();
        parts.AddApplicationPart(typeof(EchoClient).Assembly).WithReferences();
    })
    .AddGrainService<EchoGrainService>()
    .ConfigureServices((hostCtx, services) =>
        services.AddSingleton<IEchoClient, EchoClient>()
    );
}

Usage from an API controller:

[Route("[controller]")]
[ApiController]
public class TestController : ControllerBase
{
    private readonly IEchoClient EchoClient;

    public TestController(IEchoClient echoClient)
    {
        EchoClient = echoClient;
    }

    [HttpGet]
    public Task<string> Get()
    {
        return EchoClient.Echo("ping");
    }
}

Exception thrown for any reference to GrainService in the client object:

NullReferenceException: Object reference not set to an instance of an object. Orleans.Runtime.Services.GrainServiceClient<TGrainService>.MapGrainReferenceToSiloRing(GrainReference grainRef) Orleans.Runtime.Services.GrainServiceClient<TGrainService>.get_GrainService() Test.SimpleGrainService.EchoClient.Echo(string input) in EchoClient.cs => GrainService.Echo(input); BTPAPI.Controllers.TestController.Get() in TestController.cs return EchoClient.Echo("ping"); lambda_method(Closure , object , object[] )

mv10-work avatar Nov 20 '19 15:11 mv10-work

Minimal console-based reproduction using v3.0.2

https://github.com/MV10/OrleansGrainServiceTest

MV10 avatar Dec 29 '19 12:12 MV10

After looking at the GrainServiceClient code, it appears they can only be invoked by grains.

https://github.com/dotnet/orleans/blob/master/src/Orleans.Runtime/Services/GrainServiceClient.cs#L45 https://github.com/dotnet/orleans/blob/master/src/Orleans.Runtime/Services/GrainServiceClient.cs#L56

This can be inferred from comments midway through the docs ("Step 3. Create an interface for the GrainServiceClient to be used by other grains..." and "Step 5. Inject the grain service client into the other grains that need it.") but it seems like a pretty important restriction that should be stated up front.

MV10 avatar Dec 29 '19 13:12 MV10

I've replaced the usage of grain services on filters to use Channel<T>...

galvesribeiro avatar Dec 29 '19 14:12 galvesribeiro

@galvesribeiro I'm running into this issue as well. What do you mean by saying to use Channel<T>?

joshzngf avatar Dec 10 '20 06:12 joshzngf

@joshzngf sorry the long delay, never saw your reply.

I've started using https://docs.microsoft.com/en-us/dotnet/api/system.threading.channels.channel-1?view=net-6.0 instead of the grain service for this case since GrainServices can only be invoked from within a grain context.

galvesribeiro avatar Dec 02 '21 23:12 galvesribeiro

We've moved this issue to the Backlog. This means that it is not going to be worked on for the coming release. We review items in the backlog at the end of each milestone/release and depending on the team's priority we may reconsider this issue for the following milestone.

ghost avatar Jul 28 '22 23:07 ghost