Orleans: Unable to invoke GrainService from Filter

Created on 2 Aug 2019  路  4Comments  路  Source: dotnet/orleans

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!

Most helpful comment

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

All 4 comments

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.MapGrainReferenceToSiloRing(GrainReference grainRef)
Orleans.Runtime.Services.GrainServiceClient.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[] )

Minimal console-based reproduction using v3.0.2

https://github.com/MV10/OrleansGrainServiceTest

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.

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

Was this page helpful?
0 / 5 - 0 ratings