MVC Core 2 SignalR и длительные процессы - PullRequest
0 голосов
/ 29 октября 2018

Я пишу веб-приложение MVC Core 2.1 SignalR, в котором есть некоторые долгосрочные задачи. Есть ли предпочтительный шаблон для поддержки этого?

Первоначально я поместил некоторые статические элементы в концентратор, где получены сообщения на START или STOP, но это недолговечные объекты, и хотя статические члены все еще обрабатывали, экземпляр, из которого был запущен код, удаляется или исчезает, хотя предполагается, что более поздние сообщения могут вызвать остановку.

Take-2 - использовать Singleton, который содержит метод, который может быть запущен или остановлен по мере необходимости. Поскольку теперь это выполняется за пределами концентратора, мы должны внедрить его в работающий процесс для обновления прогресса.

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

Любые мысли приветствуются

public class MySingletonWorker : ScopedProcessor
{
    public bool IsRunning { get; private set; } = false;

    CancellationTokenSource _cts;

    public MySingletonWorker(IServiceScopeFactory serviceScopeFactory) : base(serviceScopeFactory)
    {
    }

    public void RunTheProcess()
    {
        if (!this.IsRunning)
        {
            this.IsRunning = true;

            var scope = _serviceScopeFactory.CreateScope();
            _cts = scope.ServiceProvider.GetService<CancellationTokenSource>();
            var hub = scope.ServiceProvider.GetService<IHubContext<MyHub>>();

            Task.Run(async () =>
            {
                await WorkerMethod(_cts.Token, hub);

                this.IsRunning = false;
            });
        }
    }

    async Task ReportProgress(IHubContext<MyHub> hub, string msg)
    {
        if (hub != null)
        {
            await hub.Clients.All.SendAsync("ReceiveMessage", msg);
        }
    }

    async Task WorkerMethod(CancellationToken token, IHubContext<MyHub> hub)
    {
        try
        {
            await ReportProgress(hub, "Starting");

            // Assume a loop of some kind iterates the work to do
            while (true != false)
            {
                // work done here

                // Cancelled?
                if (token.IsCancellationRequested)
                {
                    token.ThrowIfCancellationRequested();
                }
            }
        }
        catch (OperationCanceledException exoc)
        {
            await ReportProgress(hub, exoc.Message);
        }
        catch (System.Exception ex)
        {
            await ReportProgress(hub, ex.Message);
        }
        finally
        {
            await ReportProgress(hub, "Finished");
        }
    }

    public void CancellProcess()
    {
        if (_cts != null)
        {
            _cts.Cancel();
        }
    }

    protected override async Task ExecuteAsync(CancellationToken ct)
    {
        await Task.Run(() =>
        {
        });

    }
}
...