Service Fabric,确定特定参与者是否存在
Service Fabric, determine if specific actor exists
我们正在使用 Azure Service Fabric 并使用 actors 对特定设备进行建模,使用设备的 ID 作为 ActorId
。如果尚未实例化,Service Fabric 将在我们为给定 id 请求 actor 时实例化一个新的 actor 实例,但我似乎找不到 api 允许我查询特定设备 id 是否已经实例化演员.
我知道在获取时间点真相时可能存在一些 distributed/timing 问题,但出于我们的特定目的,我们不需要对此进行硬性实时回答,但可以接受最佳猜测.从理论上讲,我们只想联系 ActorId
解析的特定分区的当前主设备,并返回设备是否具有实例化的 actor。
理想情况下,它是一个 fast/performant 调用,基本上比例如实例化演员并调用一个方法来了解它是否已正确初始化并且不仅仅是一个 "empty" 演员。
您可以使用 ActorServiceProxy
循环访问特定分区的信息,但这似乎不是一种获取信息的高效方法。
有人对此有深入的了解吗?
唯一可以检查 actor 之前是否已在任何服务分区中激活的官方方法是使用 ActorServiceProxy
查询,如 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 的性质,它们是虚拟的,这意味着它们始终存在,即使您之前没有激活,所以做这个检查有点困难。
如您所说,查询所有参与者的性能不佳,因此,您可以尝试的其他解决方法是:
将 ID 存储在别处的可靠字典中,每次激活 Actor 时,您都会引发事件并在字典中插入 ActorID(如果字典中还没有的话)。
- 您可以使用
OnActivateAsync()
actor 事件来通知它的创建,或者
- 您可以使用 ActorService 中的自定义 actor 工厂来注册 actor 激活
- 您可以将字典存储在另一个 actor 或另一个 StatefulService 中
在actor中创建一个属性激活时由actor自己设置的
OnActivateAsync()
检查这个属性之前是否设置过
- 如果尚未设置,您可以设置一个新值并存储在一个变量(非持久化值)中以表示演员是新的
- 每当你与演员互动时,你都会设置它来表明它不再是新的
- 下次激活时,属性 已经设置好,不会发生任何事情。
创建一个自定义 IActorStateProvider 来执行选项 2 中提到的相同操作,而不是在 actor 中处理它,它将处理它下面的一个级别。老实说,我认为这有点工作,只有当你必须对许多演员类型做同样的事情时才会方便,选项 1 和 2 会容易得多。
按照 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
}
或者,您可以创建一个有状态的 DeviceActorStatusActor
,它会在创建后立即由 DeviceActor
通知(调用)。 (分享 ActorId 以进行关联。)
根据您的需要,您还可以使用相同的状态跟踪 actor 注册多个 Actor。
您将获得出色的性能和近乎实时的信息。
我们正在使用 Azure Service Fabric 并使用 actors 对特定设备进行建模,使用设备的 ID 作为 ActorId
。如果尚未实例化,Service Fabric 将在我们为给定 id 请求 actor 时实例化一个新的 actor 实例,但我似乎找不到 api 允许我查询特定设备 id 是否已经实例化演员.
我知道在获取时间点真相时可能存在一些 distributed/timing 问题,但出于我们的特定目的,我们不需要对此进行硬性实时回答,但可以接受最佳猜测.从理论上讲,我们只想联系 ActorId
解析的特定分区的当前主设备,并返回设备是否具有实例化的 actor。
理想情况下,它是一个 fast/performant 调用,基本上比例如实例化演员并调用一个方法来了解它是否已正确初始化并且不仅仅是一个 "empty" 演员。
您可以使用 ActorServiceProxy
循环访问特定分区的信息,但这似乎不是一种获取信息的高效方法。
有人对此有深入的了解吗?
唯一可以检查 actor 之前是否已在任何服务分区中激活的官方方法是使用 ActorServiceProxy
查询,如 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 的性质,它们是虚拟的,这意味着它们始终存在,即使您之前没有激活,所以做这个检查有点困难。
如您所说,查询所有参与者的性能不佳,因此,您可以尝试的其他解决方法是:
将 ID 存储在别处的可靠字典中,每次激活 Actor 时,您都会引发事件并在字典中插入 ActorID(如果字典中还没有的话)。
- 您可以使用
OnActivateAsync()
actor 事件来通知它的创建,或者 - 您可以使用 ActorService 中的自定义 actor 工厂来注册 actor 激活
- 您可以将字典存储在另一个 actor 或另一个 StatefulService 中
- 您可以使用
在actor中创建一个属性激活时由actor自己设置的
OnActivateAsync()
检查这个属性之前是否设置过- 如果尚未设置,您可以设置一个新值并存储在一个变量(非持久化值)中以表示演员是新的
- 每当你与演员互动时,你都会设置它来表明它不再是新的
- 下次激活时,属性 已经设置好,不会发生任何事情。
创建一个自定义 IActorStateProvider 来执行选项 2 中提到的相同操作,而不是在 actor 中处理它,它将处理它下面的一个级别。老实说,我认为这有点工作,只有当你必须对许多演员类型做同样的事情时才会方便,选项 1 和 2 会容易得多。
按照 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
}
或者,您可以创建一个有状态的 DeviceActorStatusActor
,它会在创建后立即由 DeviceActor
通知(调用)。 (分享 ActorId 以进行关联。)
根据您的需要,您还可以使用相同的状态跟踪 actor 注册多个 Actor。
您将获得出色的性能和近乎实时的信息。