【问题标题】:Can't confirm any actors are being created无法确认正在创建任何演员
【发布时间】:2025-12-08 23:50:02
【问题描述】:

在 Service Fabric 中,我尝试调用 ActorService 并获取所有演员的列表。我没有收到任何错误,但没有返回任何演员。它始终为零。

这就是我添加演员的方式:

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

这就是我尝试获取所有演员列表的方式:

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);

但是无论我添加了多少用户,页面对象总是有零项。我错过了什么?

【问题讨论】:

    标签: azure azure-service-fabric actor


    【解决方案1】:

    ActorServiceProxy.Create(Uri, int, string) 中的第二个参数int 是分区键(您可以找到有关演员分区here 的更多信息)。

    这里的问题是您的代码只检查 一个 分区 (partitionKey = 0)。

    所以解决方案非常简单——您必须遍历服务的所有分区。这是一个answer 代码示例,用于获取分区并对其进行迭代。

    更新 2019.07.01


    我从一开始就没有发现这一点,但是您没有返回任何演员的原因是因为您没有创建任何演员 - 您正在创建代理!

    造成这种混淆的原因是 Service Fabric Actor 是虚拟的,即从用户的角度来看 Actor 始终存在,但在现实生活中 Service Fabric 管理 Actor 对象的生命周期,自动持久化并根据需要恢复其状态。

    这是documentation的引述:

    一个actor被自动激活(导致一个actor对象被构造)第一次向它的actor ID发送消息时。一段时间后,actor对象被垃圾回收。将来,再次使用演员 ID 会导致构造一个新的演员对象。当存储在状态管理器中时,参与者的状态比对象的生命周期更长。

    在您的示例中,您从未向演员发送任何消息!

    这是我在Program.cs 新创建的 Actor 项目中编写的代码示例:

    // 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);
    

    特别注意行:

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

    这里是发送给actor的第一条消息的地方。


    希望这会有所帮助。

    【讨论】:

    • 感谢您抽出宝贵时间!但我看不出该代码如何产生任何影响。首先,我只有一个分区。其次,它对每个分区做同样的事情。它使用低键作为分区键,每个分区都一样吗?
    • 另外,我在您链接的代码中看到 Create 方法使用 IMyService 类型。这是必要的还是它也适用于 IActorService?因为我的 ActorService 还没有自己的服务类型。无论如何,我遍历了分区,但没有返回任何内容。它是空的。在尝试列出之前,我确保添加了三个演员。
    • OMFG!这真太了不起了。当然。所以实际上我应该认为演员是不持久的。只有他们的状态是持久的。因此,如果我不将状态分配给某个 ID,则不会保存任何内容。如果一个 ID 有一个状态,那么就会保存关于那个演员的元数据。正确的?我今晚会试试这个。
    • 成功了!谢谢你教我这个基础。在接下来的几周内,我肯定会在这里发布更多 SF 问题,但现在我已经准备好开始探索了。