Search code examples
c#azure-service-fabricservice-fabric-actor

Spawning actors in RunAsync throws "Interface id '1830616258' is not implemented by object 'CustomActorService.InternalCustomActorService'"


I am following the advice in Service Fabric spawn actor on startup for spawning a couple of actors at service start. I have a custom ActorService subclass with the following RunAsync override:

internal sealed class InternalCustomActorService : ActorService
{
  protected async override Task RunAsync(CancellationToken cancellationToken)
  {
    await base.RunAsync(cancellationToken);

    for(int i = 0; i < 10; i++)
    {
      ICustomActor proxy = ActorProxy.Create<ICustomActor>(new ActorId(i));
      await proxy.StartAsync();
    }
  }
...

The class is registered in Program.cs as follows:

    ActorRuntime.RegisterActorAsync<CustomActor>(
       (context, actorType) => new InternalCustomActorService(context, actorType, () => new CustomActor())).GetAwaiter().GetResult();

However, I am getting the following exception calling proxy.StartAsync() method:

FatalExecutionEngineError occurred
  HResult=-2146233088
  Message=One or more errors occurred.
  Source=Microsoft.ServiceFabric.Services
  StackTrace:
       at Microsoft.ServiceFabric.Services.Communication.Client.ServicePartitionClient`1.<InvokeWithRetryAsync>d__7`1.MoveNext()
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at Microsoft.ServiceFabric.Services.Remoting.Client.ServiceRemotingPartitionClient.<InvokeAsync>d__8.MoveNext()
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at Microsoft.ServiceFabric.Services.Remoting.Builder.ProxyBase.<InvokeAsync>d__0.MoveNext()
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at Microsoft.ServiceFabric.Services.Remoting.Builder.ProxyBase.<ContinueWith>d__b.MoveNext()
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
       at CustomActorService.InternalCustomActorService.<RunAsync>d__2.MoveNext() in C:\_data\Master\CONSTABLE2\Apps\BSP\Research\ServiceFabric\CustomActorServiceApp\CustomActorService\InternalCustomActorService.cs:line 47
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at Microsoft.ServiceFabric.Services.Runtime.StatefulServiceReplicaAdapter.<ExecuteRunAsync>d__e.MoveNext()
  InnerException: 
       HResult=-2147467263
       Message=Interface id '1830616258' is not implemented by object 'CustomActorService.InternalCustomActorService'
       Source=Microsoft.ServiceFabric.Services
       InnerException: 

The sample project is on GitHub here https://github.com/PaloMraz/CustomActorServiceApp

My question is: what am I doing wrong?

EDIT: I have tried to add additional BootstrapperService stateless service and spawn the actors from there in BootstrapperService.RunAsync:

protected override async Task RunAsync(CancellationToken cancellationToken)
{
  await base.RunAsync(cancellationToken);
  await Task.Delay(10000);

  for (int i = 0; i < 10; i++)
  {
    ICustomActor proxy = ActorProxy.Create<ICustomActor>(new ActorId(i));
    await proxy.StartAsync();
  }
}

Nevertheless, the call to proxy.StartAsync() throws the exact same exception as from within the InternalCustomActorService.RunAsync above.


Solution

  • Remove the following code from your custom actor service:

         protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners() 
     { 
       var remotingListener = new ServiceReplicaListener(context => this.CreateServiceRemotingListener(context)); 
       return new ServiceReplicaListener[] { remotingListener }; 
     } 
    

    This is removing the ActorRemotingListener that the base ActorService is setting up. If you would like to add additional listener, call the base CreateServiceReplicaListeners method, get the listeners and then add custom listener.