服务结构,确定是否存在特定角色

时间:2018-10-31 08:59:23

标签: azure-service-fabric service-fabric-actor

我们正在使用Azure Service Fabric,并且正在使用参与者对特定设备进行建模,并将设备的ID用作ActorId。当我们请求给定角色的actor(如果尚未实例化)时,Service Fabric将实例化一个新的actor实例,但是我似乎找不到一个可以让我查询特定设备ID是否已实例化actor的api。 >

我知道在获取时间点真相时可能会存在一些分布式/时序问题,但是出于我们的特定目的,我们不需要对此进行实时的硬性解答,但可以做出最佳猜测。从理论上讲,我们只想联系ActorId解析的特定分区的当前主节点,并获取设备是否具有实例化actor的信息。

理想情况下,这是一个快速/高效的通话,本质上比例如实例化actor并调用方法以了解它是否已正确初始化,而不仅仅是一个“空” actor。

您可以使用ActorServiceProxy遍历特定分区的信息,但这似乎并不是获取信息的非常有效的方法。

有人对此有见识吗?

2 个答案:

答案 0 :(得分:0)

您可以使用以前的ActorServiceProxy查询来检查actor是否已在任何服务分区中被激活,这是唯一的官方方法,如here所述:

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 Actor的性质,它们是虚拟的,这意味着它们始终存在,即使您之前没有激活过,因此进行此项检查会变得更加困难。

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

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

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

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

  4. 作为 Peter Bons 进行操作建议将ActorID存储在ActorService外部,例如存储在数据库中,仅当您必须从集群外部进行检查时,我才建议您使用此选项

如果要在actor之外管理这些事件,则以下摘录内容可以为您提供帮助。

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
}

答案 1 :(得分:0)

或者,您可以创建一个有状态的DeviceActorStatusActor,该状态将在创建后立即由DeviceActor通知(调用)。 (共享ActorId进行关联。)

根据您的需要,您还可以向同一状态跟踪演员注册多个演员。

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