Очередь длинных задач в веб-приложении

Пользователь может выполнить действие в нашем веб-приложении, которое занимает от 100 мс до 10 секунд, я хочу немедленно вернуть результат браузеру и затем показать результаты пользователю после завершения обработки задачи. Действие - синхронизация данных от третьей стороны и реализуется как библиотека классов (DLL).

Обычно он предлагал использовать очередь, такую ​​как RabbitMQ или MSMQ, и иметь рабочего, который записывает результаты в базу данных, которая опрошена по запросу AJAX из браузера, чтобы проверить наличие обновлений.

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

Как создать резервную копию бэкэнда?. На мой взгляд, процесс будет состоять в следующем: запуск задачи, запуск задачи с минимальной задержкой, уведомление конечного пользователя о завершении задачи (ASAP) и, наконец, отображение результатов в браузере.

Long Running Task. Credits: Haishi. Source: <code>http://haishibai.blogspot.co.uk/2012/12/dealing-with-long-running-jobs.html</code>

<сильные > Примеры

Создание sitemaps с http://www.xml-sitemaps.com/ использует закодированное кодирование передачи для отправки тега <script> каждую секунду, чтобы вызвать функцию Javascript для обновления страницы с последним статусом.

Проверка сертификатов SSL с https://www.ssllabs.com/ssltest/, похоже, обновляет всю страницу с обновленным статусом.

Ответ 1

Эта ситуация относительно проста, и я бы не стал рекомендовать опрос вообще.

Рассмотрим использование обычного подхода Ajax: часть страницы может обновляться без остальной части страницы. Так что часть (часть ajax) является синхронной сама по себе, но асинхронна со всей точки зрения страницы (потому что она обновляется без перезагрузки всей страницы).

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

Преимущество в том, что у вас нет опроса, а результаты сразу отображаются на экране (как можно скорее). Кроме того, только один запрос работает над этим, вместо нескольких, возможно, пропущенных запросов при опросе.

Ответ 2

Рассматривали ли вы использование WF4 в сочетании с SignalR?

Мы используем WF4 для обработки обратной обработки, и она работает довольно хорошо. Мы сохраняем запросы в таблице запросов на работу, механизм документооборота (служба, которую мы написали, которая запускает wf4 в бэкэнд) берет запрос, обрабатывает работу и затем отмечает задание как завершенное.

SignalR затем может использоваться для информирования клиента о завершении задания. Масштабирование относительно просто (посмеиваясь, поскольку я знаю, что "легко" его всегда чревато деталями), поскольку вы можете развернуть больше сервисов для обработки запросов. Каждый движок будет отмечать запрос как обработанный, чтобы другие его не подбирали.

Я использовал wf4 для крупномасштабных проектов, где услуги были сбалансированы по нагрузке, и мы смогли получить очень приличную пропускную способность.

Ответ 3

FWIW, если вы действительно не хотите инвестировать в полномасштабное решение на основе очереди, вы можете использовать TPL + SignalR (или любая такая библиотека Comet) для обработки вашего долгого запроса и отправки обратной связи клиенту.

Итак, идея такова:

  • Клиент отправляет запрос на сервер
  • Сервер запускает обработку фона через TPL
  • Сервер уведомляет клиента об обновлениях через SignalR

Что-то вроде этого (используя TPL и SignalR):

//сервер

public class MyHub : Hub
{

    public void Start()
    {
         var longRunningTask = Task.Factory.StartNew(() =>
            {
                var someService = new someService();
                // do stuff
                someService.doSomething();
                Clients.All.longRunningTask(<data>);    

            }, TaskCreationOptions.LongRunning);
    }
}

// initiating from your asp.net page (codebehind or via ajax or any which way)
new MyHub().Start();

//клиент

var hub = $.connection.myHub;
hub.client.longRunningTask = function (data) {
     // do something with data
}

Это очень низкая латентность, не требует очереди и позволяет выталкивать обновления по мере их поступления (просто вызов Clients.All.longRunningTask будет вызывать обновление клиенту).

Литература:

Начало работы с SignalR 2

Ответ 4

Это может быть немного упрощенным, но самым простым способом может быть длительный опрос на клиенте.

т.е.: отправить запрос на работу в GET-запрос, вернуть токен. Затем немедленно запросите результат этого токена и пусть сервер блокирует ответ. Если запрос истечет, перезапустите его. На стороне сервера просто заблокируйте этот поток, ожидая завершения задачи. Даже самые агрессивные балансировочные балансы позволят довести до времени зависания.

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

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