Отмена долгосрочного задания при условии - PullRequest
0 голосов
/ 11 июня 2019

Я запускаю связанную с процессором задачу в приложении asp.net mvc.Некоторые пользователи могут «подписаться» на эту задачу, и они должны быть уведомлены о завершении.Но если у задания нет подписчиков, оно должно быть отменено.Задача запускается через ajax-запрос и отменяется при вызове метода .abort ().В контроллере у меня есть CancellationToken в качестве параметра, который определяет отмену.

Проблема в том, что когда один из абонентов вызывает прерывание (отписывается), связанный токен отменяет задачу, несмотря на то, что другие пользователи ждут результата.Как я могу отменить CancellationToken после проверки некоторых условий?Я не могу проверить реквизиты IsCancellationRequested после каждой итерации цикла, потому что я обертываю не асинхронный метод.

Пользователи получают уведомление с SignalR после завершения задачи.Я попытался реализовать ConcurrentDictionary, чтобы проверить перед отменой, есть ли у задачи подписчики или нет.

private async Task<Diff> CompareAsync(Model modelName, CancellationToken ct)
        {
            try
            {
                return await Task.Factory.StartNew(() =>
                {
                    ct.ThrowIfCancellationRequested();

                        return _someServiceName.CompareLines(modelName.LinesA, modelName.LinesB, ct);


                }, ct, TaskCreationOptions.LongRunning, TaskScheduler.Default).ConfigureAwait(false);
            }
            catch (OperationCanceledException)
            {

                //do some things
            }

        }

Мне нужно что-то подобное, но я не могу придумать (не уродливые) идеи:

private async Task<Diff> CompareAsync(Model modelName, CancellationToken ct)
        {
            try
            {
                return await Task.Factory.StartNew(() =>
                {
                    using (var source = new CancellationTokenSource())
                    {

                        if (ct.IsCancellationRequested && CompareService.SharedComparison.TryGetValue(modelName.Hash, out var usersCount) && usersCount < 2)
                        {
                            source.Cancel();

                        }

                        return _someServiceName.CompareLines(modelName.LinesA, modelName.LinesB, source.Token);  
                    }


                }, ct, TaskCreationOptions.LongRunning, TaskScheduler.Default).ConfigureAwait(false);
            }
            catch (OperationCanceledException)
            {

                //do some things
            }

        }

1 Ответ

0 голосов
/ 11 июня 2019

Вам нужно будет поддерживать потокобезопасный счетчик подписчиков (скорее всего, с помощью lock) и отменять токен только тогда, когда его 0.

private int _subscribers;
private object _sync = new object();

private AddSubscribers()
{
   Lock(_sync )
   {
       // do what ever you need to do
       _subscribers++;
   }
}

private RemoveSubscribers()
{
   Lock(_sync )
   {
       // do what ever you need to do
       _subscribers--;
       if(_subscribers <= 0)
       {
           // cancel token
       }
   }
}

Примечание : Очевидно, это не полное решение и многое оставляет для воображения

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...