Сервис Ткань самоудерживающийся сервис - PullRequest
0 голосов
/ 21 мая 2018

Я хотел бы добавить службу, которая выполняет некоторые операции инициализации системы при ее первом создании.

Я бы предположил, что это будет служба без сохранения состояния (с правами администратора кластера), которая должна самостоятельноуничтожить, когда это сделано, это вещь.Я под впечатлением, что выход из функции RunAsync позволяет мне указать, что я закончил (или в состоянии ошибки).Тем не менее, он все еще зависает в контексте приложения и досадно выглядит так, как будто он «активен», когда он вообще ничего не делает.

Возможно ли, чтобы служба удалила себя?

Я думаю, может быть, мы могли бы попытаться использовать FabricClient.ServiceManager DeleteServiceAsync (используя параметры, основанные на контексте службы) внутри переопределения OnCloseAsync, но я не смог доказать, что это может работать, и это выглядит немного странно:

var client = new FabricClient();
await client.ServiceManager.DeleteServiceAsync(new DeleteServiceDescription(Context.ServiceName));

Есть ли лучший способ?

Ответы [ 2 ]

0 голосов
/ 19 октября 2018

Как уже упоминалось, возврат из RunAsync завершит только этот метод, но служба продолжит работу и, следовательно, не будет удалена.

DeleteServiceAsync, безусловно, это путь, однако это не совсем такпросто, просто позвонив, потому что, если вы не будете осторожны, он заблокирует текущий поток (особенно в локальном кластере разработчиков).Скорее всего, вы также получите несколько кратковременных предупреждений о работоспособности, связанных с тем, что RunAsync требует много времени для завершения и / или не соответствует целевому размеру реплики.

В любом случае - решение довольно простое - просто сделайте это:

private async Task DeleteSelf(CancellationToken cancellationToken)
{
       using (var client = new FabricClient())
       {
            await client.ServiceManager.DeleteServiceAsync(new DeleteServiceDescription(this.Context.ServiceName), TimeSpan.FromMinutes(1), cancellationToken);
       }
}

Затем в последней строке моего метода RunAsync я вызываю:

await DeleteSelf(cancellationToken).ConfigureAwait(false);

ConfigureAwait(false) поможет с проблемой взаимоблокировки, поскольку он по существу вернется к новому контексту синхронизации потока - т.е. не попытается вернуться к «контексту вызывающего».

0 голосов
/ 22 мая 2018

Возврат из RunAsync приведет к завершению кода в RunAsync (указать завершение), поэтому SF не запустит RunAsync снова (например, если он вернул исключение).Завершение RunAsync не приводит к удалению службы .Как уже упоминалось, например, служба может выполняться с фоновой работой, но при этом прослушивать входящие сообщения.

Лучший способ закрыть сервис - это вызвать DeleteServiceAsync.Это может быть сделано самой службой или другой службой, или снаружи кластера.Службы могут быть удалены самостоятельно, поэтому для служб, работа которых выполнена, мы обычно ожидаем DeleteServiceAsync в качестве последней строки RunAsync, после чего метод просто завершается.Что-то вроде:

RunAsync(CancellationToken ct)
{
    while(!workCompleted && !ct.IsCancellationRequested)
    {
        if(!DoneWithWork())
        {
            DoWork()
        }

        if(DoneWithWork())
        {
            workCompleted == true;
            await DeleteServiceAsync(...) 
        }
    }
}

Цель состоит в том, чтобы гарантировать, что, если ваш сервис действительно выполняет свою работу, он очищает себя, но не запускает собственное удаление по другим причинам, по которым может быть сигнализирован CancellationTokenНапример, завершение работы из-за некоторого обновления или балансировки ресурсов кластера.

...