Daarwin
Daarwin

Reputation: 3014

Can't confirm any actors are being created

In Service Fabric I am trying to call an ActorService and get a list of all actors. I'm not getting any errors, but no actors are returned. It's always zero.

This is how I add actors :

ActorProxy.Create<IUserActor>(
  new ActorId(uniqueName), 
  "fabric:/ECommerce/UserActorService");

And this is how I try to get a list of all actors:

var proxy = ActorServiceProxy.Create(new Uri("fabric:/ECommerce/UserActorService"), 0);

ContinuationToken continuationToken = null;
CancellationToken cancellationToken = new CancellationTokenSource().Token;
List<ActorInformation> activeActors = new List<ActorInformation>();

do
{
  var proxy = GetUserActorServiceProxy();
  PagedResult<ActorInformation> page = await proxy.GetActorsAsync(continuationToken, cancellationToken);

  activeActors.AddRange(page.Items.Where(x => x.IsActive));

  continuationToken = page.ContinuationToken;
}
while (continuationToken != null);

But no matter how many users I've added, the page object will always have zero items. What am I missing?

Upvotes: 1

Views: 88

Answers (1)

Oleg Karasik
Oleg Karasik

Reputation: 969

The second argument int in ActorServiceProxy.Create(Uri, int, string) is the partition key (you can find out more about actor partitioning here).

The issue here is that your code checks only one partition (partitionKey = 0).

So the solutions is quite simple - you have to iterate over all partitions of you service. Here is an answer with code sample to get partitions and iterate over them.

UPDATE 2019.07.01


I didn't spot this from the first time but the reason why you aren't getting any actors returned is because you aren't creating any actors - you are creating proxies!

The reason for such confusion is that Service Fabric actors are virtual i.e. from the user point of view actor always exists but in real life Service Fabric manages actor object lifetime automatically persisting and restoring it's state as needed.

Here is a quote from the documentation:

An actor is automatically activated (causing an actor object to be constructed) the first time a message is sent to its actor ID. After some period of time, the actor object is garbage collected. In the future, using the actor ID again, causes a new actor object to be constructed. An actor's state outlives the object's lifetime when stored in the state manager.

In you example you've never send any messages to actors!

Here is a code example I wrote in Program.cs of newly created Actor project:

// Please don't forget to replace "fabric:/Application16/Actor1ActorService" with your actor service name.

ActorRuntime.RegisterActorAsync<Actor1> (
  (context, actorType) => 
    new ActorService(context, actorType)).GetAwaiter().GetResult();

var actor = ActorProxy.Create<IActor1>(
  ActorId.CreateRandom(),
  new Uri("fabric:/Application16/Actor1ActorService"));

_ = actor.GetCountAsync(default).GetAwaiter().GetResult();

ContinuationToken continuationToken = null;
var activeActors = new List<ActorInformation>();

var serviceName = new Uri("fabric:/Application16/Actor1ActorService");
using (var client = new FabricClient())
{
  var partitions = client.QueryManager.GetPartitionListAsync(serviceName).GetAwaiter().GetResult();;

  foreach (var partition in partitions)
  {
    var pi = (Int64RangePartitionInformation) partition.PartitionInformation;
    var proxy = ActorServiceProxy.Create(new Uri("fabric:/Application16/Actor1ActorService"), pi.LowKey);
    var page = proxy.GetActorsAsync(continuationToken, default).GetAwaiter().GetResult();

    activeActors.AddRange(page.Items);

    continuationToken = page.ContinuationToken;
  }
}

Thread.Sleep(Timeout.Infinite);

Pay special attention to the line:

_ = actor.GetCountAsync(default).GetAwaiter().GetResult();

Here is where the first message to actor is sent.


Hope this helps.

Upvotes: 1

Related Questions