1

我们正在使用 Azure Service Fabric,并使用参与者对特定设备进行建模,使用设备的 id 作为ActorId. 当我们为给定 id 请求一个演员时,如果它尚未实例化,Service Fabric 将实例化一个新的演员实例,但我似乎找不到允许我查询特定设备 ID 是否已经实例化演员的 api。

我知道在获取时间点真相时可能存在一些分布式/时间问题,但出于我们的特定目的,我们不需要硬实时答案,但可以满足于最佳猜测。理论上,我们只想联系当前主ActorId节点以获取由 解析的特定分区,并返回设备是否具有实例化的参与者。

理想情况下,它是一个快速/高性能的调用,基本上比实例化actor 和调用方法来了解它是否已正确初始化并且不仅仅是一个“空”actor 更快。

您可以使用ActorServiceProxy来遍历特定分区的信息,但这似乎不是获取信息的一种非常高效的方式。

有对此有见解的人吗?

4

2 回答 2

1

您可以检查先前是否已在任何服务分区中激活参与者的唯一官方方法是使用查询ActorServiceProxy,如下所述:

IActorService actorServiceProxy = ActorServiceProxy.Create(
    new Uri("fabric:/MyApp/MyService"), partitionKey);

ContinuationToken continuationToken = null;
do
{
    PagedResult<ActorInformation> page = await actorServiceProxy.GetActorsAsync(continuationToken, cancellationToken);

    var actor = page.Items.FirstOrDefault(x => x.ActorId == idToFind);

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

根据 SF Actors 的性质,它们是虚拟的,这意味着它们始终存在,即使您之前没有激活,因此执行此检查有点困难。

正如您所说,查询所有参与者并不高效,因此,您可以尝试的其他解决方法是:

  1. 将 ID 存储在其他地方的可靠字典中,每次激活 Actor 时,您都会引发事件并将 ActorID 插入字典中(如果还没有的话)。

    • 您可以使用OnActivateAsync()actor 事件来通知它的创建,或者
    • 您可以使用 ActorService 中的自定义actor工厂来注册actor激活
    • 您可以将字典存储在另一个参与者或另一个 StatefulService
  2. 在 Actor 中创建一个属性,该属性由 Actor 自己在激活时设置。

    • 检查此OnActivateAsync()属性之前是否已设置
    • 如果尚未设置,则设置一个新值并存储在一个变量(非持久值)中,以说明该演员是新的
    • 每当您与演员互动时,您都会设置它以表明它不再是新的
    • 下一次激活时,该属性将已设置,并且不会发生任何事情。
  3. 创建一个自定义 IActorStateProvider 来执行选项 2 中提到的相同操作,而不是在 actor 中处理它,而是在它下面处理一个级别。老实说,我认为这有点工作,只有当你必须对许多演员类型做同样的事情时才会很方便,选项 1 和 2 会容易得多。

  4. 按照Peter Bons的建议,将 ActorID 存储在 ActorService 之外,就像在数据库中一样,如果您必须从集群外部进行检查,我只会建议使用此选项

.

如果您想在演员之外管理这些事件,以下片段可以帮助您。

private static void Main()
{
    try
    {
        ActorRuntime.RegisterActorAsync<NetCoreActorService>(
           (context, actorType) => new ActorService(context, actorType,
                    new Func<ActorService, ActorId, ActorBase>((actorService, actorId) =>
                    {
                        RegisterActor(actorId);//The custom method to register the actor if new
                        return (ActorBase)Activator.CreateInstance(actorType.ImplementationType, actorService, actorId);
                    })
                )).GetAwaiter().GetResult();

        Thread.Sleep(Timeout.Infinite);
    }
    catch (Exception e)
    {
        ActorEventSource.Current.ActorHostInitializationFailed(e.ToString());
        throw;
    }
}

private static void RegisterActor(ActorId actorId) 
{
    //Here you will put the logic to register elsewhere the actor creation
}
于 2018-10-31T11:54:56.070 回答
0

或者,您可以创建一个有状态的,一旦创建DeviceActorStatusActor就会被通知(调用)DeviceActor。(共享 ActorId 以进行关联。)

根据您的需要,您还可以使用相同的状态跟踪 Actor 注册多个 Actor。

您将获得出色的性能和近乎实时的信息。

于 2018-10-31T15:38:14.047 回答