Запускайте чрезвычайно долго запущенные процессы через запрос REST - PullRequest
1 голос
/ 06 июня 2019

Я работаю в фирме по автоматизации, поэтому мы создаем процессы для промышленной автоматизации.Ранее эта автоматизация выполнялась на стороне машин, но мы постепенно переходим к управлению машинами с помощью c #.

В моем текущем проекте производство за один день занимает около 2 часов.Операторы фабрики имеют веб-интерфейс, который мы создали в c # с использованием ядра MVC asp.net, в котором они могут запустить / приостановить / остановить этот производственный процесс.

При запуске процесса мы ожидаем функцию в нашем контроллереэто в основном цикл while, который контролирует этот 2-часовой процесс производства.

Проблема в том, что когда я отправляю запрос REST для запуска производства, этот запрос занимает 2 часа, я бы предпочел, чтобы этот запрос немедленно завершился.и производственный процесс начинается на фоне моего основного приложения asp.net.

Сначала я подумал, что могу просто пропустить ожидание и просто сделать это в моем контроллере (упрощенный код):

_ = _productionController.StartLongProcess(); // This contains the while loop
return Ok();

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

Процесс должен иметь возможность непрерывнопоговорить с нашей базой данных, чтобы сохранить информацию оПроизводственный процесс в случае, если что-то выходит из строя, таким образом, мы всегда можем отследить, где остановились.

Мой вопрос к вам сейчас, не решаем ли мы это неправильно?Я полагаю, что это плохая практика - запускать эти долго работающие процессы в контроллере asp.net.

Как мне убедиться, что у меня всегда есть доступ к моему DatabaseContext в этом длительном процессе, даже если запрос REST уже завершен.Создать отдельную область только для этого метода?

Ответы [ 3 ]

2 голосов
/ 06 июня 2019

Начиная с ASP.NET Core 2.1, правильный способ сделать это (в рамках asp.net) - расширить BackgroundService (или реализовать IHostedService).

Входящие запросы могут сообщить фоновой службе:начать длительную операцию и немедленно вернуться.Вам, разумеется, нужно будет обрабатывать случаи, когда отправляются повторяющиеся запросы или новые запросы перед завершением существующего запроса.

Страница документации содержит пример , где BackgroundService читает команды очереди и обрабатывает их по одной за раз.

Как мне убедиться, что у меня всегда есть доступ к моему DatabaseContext в этом длительном процессе, даже если запрос REST уже завершен.Создать отдельную область только для этого метода?

Да, создать отдельную область.

Мой вопрос к вам сейчас, не решаем ли мы это неправильно?Я полагаю, что запускать эти длительные процессы в контроллере asp.net - плохая практика.

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

2 голосов
/ 06 июня 2019

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

Фоновая служба может быть BackGroundWroker в Net Core.это просто, но не очень устойчиво к сбоям, поэтому может пригодиться некоторая логика дБ и повторов.

Если вы находитесь в интрасети, вы также можете перейти к асинхронному протоколу по своей сути, например, RabbitMq, куда вы отправляетеStartOperation Message, а затем повторно введите сообщение Started после завершения процесса.

1 голос
/ 06 июня 2019

Ниже приводится мое понимание проблемы, которую вы опубликовали:

  1. Вы хотите начать длительный вызов через Rest api call
  2. Выхотите использовать асинхронный вызов, но не знаете, как поддерживать контекст БД для длительного вызова, который используется для связи с БД на регулярной основе во время операции

Пара важных моментов:

  1. В большинстве случаев вы не знаете, как работают асинхронные вызовы
  2. Когда вы делаете асинхронный вызов, он сохраняет текущий контекст синхронизации потока для непрерывности с использованием конечного автоматаон не блокирует какой-либо поток пула потоков, он использует аппаратный параллелизм
  3. Может использовать ConfigureAwait(false) в бэкэнде, чтобы избежать явного повторного входа в текущий контекст синхронизации, что лучше для производительности
  4. Только вызов с асинхронными вызовами, чтобы быть подлинным асинхронным, всю цепочку необходимо включить асинхронным с точки входа, иначе преимущества могутЕсли вы где-то используете Task.Wait или Task.Result, то заражение может даже вызвать тупик в ASP.Net

Что касается длительной работы, ниже приведены варианты

  1. Простой асинхронный вызов, как предложено выше, хотя он может помочь вам сделать большое количество асинхронных вызовов (таким образом, масштабируемость), но контекст будет потерян, если клиент уйдет и не сможетполучить статус операции обратно
  2. Вы можете сделать вызов и забыть о вызове и использовать механизм, подобный ASP.Net SignalR, который похож на IObservable по сети и может помочь в уведомлении клиента при обработкеfinish
  3. Наилучшим вариантом будет использование очереди сообщений, такой как Rabbit MQ, которая не рискует потерпеть неудачу, действует как потребитель-производитель и может уведомлять о появлении клиента, в этом случае MQ можетбыть уведомленным о завершении процесса, и, таким образом, клиент может быть проинформирован.MQ может использоваться как для входящего, так и для ответного сообщения в асинхронном режиме

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

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