Service Fabric, определите, существует ли конкретный субъект

Мы используем Azure Service Fabric и субъектов для моделирования конкретных устройств, используя идентификатор устройства как ActorId. Service Fabric создает новый экземпляр актора, когда мы запрашиваем у актера для данного идентификатора, если он еще не создан, но я не могу найти api, который позволяет мне запросить, есть ли у определенного идентификатора устройства уже созданный экземпляр актора.

Я понимаю, что могут возникнуть некоторые проблемы с распределением / синхронизацией при получении истины на определенный момент времени, но для нашей конкретной цели нам не нужен жесткий ответ в реальном времени, но мы можем согласиться на лучшее предположение. Теоретически мы просто хотели бы связаться с текущим первичным узлом для конкретного раздела, разрешенного ActorId, и получить обратно, есть ли на устройстве экземпляр актора.

В идеале это быстрый / эффективный вызов, существенно быстрее, чем, например, создание экземпляра актора и вызов метода, чтобы понять, правильно ли он инициализирован и не является ли он просто «пустым» актером.

Вы можете использовать ActorServiceProxy для перебора информации для определенного раздела, но это не кажется очень эффективным способом получения информации.

Кто-нибудь знает об этом?


person soren.enemaerke    schedule 31.10.2018    source источник
comment
В настоящее время нет возможности сделать это. Обходной путь может заключаться в том, чтобы субъект сохранил свой идентификатор в таблице Azure, службе с отслеживанием состояния или другом хранилище и вызвал это хранилище для получения этой информации. Вам не нужно будет активировать деактивированных акторов, чтобы они существовали таким образом.   -  person Peter Bons    schedule 31.10.2018


Ответы (2)


Единственный официальный способ проверить, был ли ранее активирован субъект в каком-либо служебном разделе, - это использовать запрос 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. Сохраните идентификаторы в надежном словаре в другом месте, каждый раз, когда актер активируется, вы вызываете событие и вставляете идентификаторы ActorID в словарь, если они еще не там.

    • You can use the OnActivateAsync() actor event to notify it's creation, or
    • Вы можете использовать фабрику пользовательских акторов в ActorService для регистрации активации акторов.
    • Вы можете сохранить словарь в другом актере или другом StatefulService
  2. Создайте свойство в актере, которое устанавливается самим актером при его активации.

    • The OnActivateAsync() check if this property has been set before
    • Если еще не установлено, вы устанавливаете новое значение и сохраняете в переменной (непостоянное значение), чтобы сказать, что актер новый.
    • Каждый раз, когда вы взаимодействуете с актером, вы устанавливаете это, чтобы указать, что он больше не новый.
    • При следующей активации свойство уже будет установлено, и ничего не должно произойти.
  3. Создайте собственный IActorStateProvider, чтобы он выполнял то же самое, что указано в варианте 2, вместо того, чтобы обрабатывать его в актере, он будет обрабатывать уровень под ним. Честно говоря, я думаю, что это небольшая работа, это будет удобно, только если вам придется проделать то же самое для многих типов актеров, варианты 1 и 2 были бы намного проще.

  4. Сделайте так, как предлагал Питер Бонс, сохраните 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
}
person Diego Mendes    schedule 31.10.2018
comment
Принимая это как ответ, так как это намечает возможные способы заставить что-то работать. - person soren.enemaerke; 01.11.2018

В качестве альтернативы вы можете создать DeviceActorStatusActor с отслеживанием состояния, который будет уведомлен (вызван) DeviceActor, как только он будет создан. (Поделитесь ActorId для корреляции.)

В зависимости от ваших потребностей вы также можете зарегистрировать несколько актеров с одним и тем же субъектом отслеживания статуса.

У вас будет отличная производительность и информация почти в реальном времени.

person LoekD    schedule 31.10.2018