Длительные задачи ASP.NET

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

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

  • Время ожидания запроса обычно истекает через 120 секунд (это настраивается), но в конечном итоге среда выполнения ASP.NET уничтожит запрос, выполнение которого занимает слишком много времени.
  • Среда хостинга, обычно IIS, использует повторное использование процессов и может в любой момент принять решение о повторном использовании вашего приложения. Когда это происходит, все потоки прерываются и приложение перезапускается. Однако я не уверен, насколько он агрессивен, было бы глупо предполагать, что он прервет обычный текущий HTTP-запрос, но я ожидаю, что он прервет поток, потому что он ничего не знает о блоке работы потока.

Если бы вам нужно было создать модель программирования, которая легко, надежно и теоретически ставит длительную задачу, которая должна выполняться в течение нескольких дней, как бы вы выполнили это из приложения ASP.NET?

Вот что я думаю по этому поводу:

Я долго думал о размещении службы WCF в службе win32. И поговорить с сервисом через WCF. Однако это не очень практично, потому что единственная причина, по которой я бы решил это сделать, — это отправлять задачи (единицы работы) из нескольких разных веб-приложений. Затем я в конечном итоге попросил бы службу обновить статус и действовал соответственно. Меня больше всего беспокоит то, что это НЕ было бы особенно хорошим опытом, если бы мне приходилось развертывать каждую задачу в службе, чтобы она могла выполнять некоторые инструкции. Есть также проблема с вводом данных: как бы я снабжал эту службу данными, если бы у меня был большой набор данных и мне нужно было его пережевывать?

Что я обычно делаю сейчас, так это

SELECT TOP 10 * 
FROM WorkItem WITH (ROWLOCK, UPDLOCK, READPAST)
WHERE WorkCompleted IS NULL

Это позволяет мне использовать базу данных SQL Server в качестве рабочей очереди и периодически опрашивать базу данных с помощью этого запроса для работы. Если рабочий элемент выполнен успешно, я отмечаю его как выполненный и продолжаю, пока больше нечего будет делать. Что мне не нравится, так это то, что теоретически меня могут прервать в любой момент, и если я нахожусь между успехом и отмечаю его как выполненный, я могу в конечном итоге обработать один и тот же рабочий элемент дважды. Я могу быть немного параноиком, и все может быть хорошо, но, как я понимаю, нет никакой гарантии, что этого не произойдет...

Я знаю, что подобные вопросы были на SO раньше, но на самом деле нет ответов с окончательным ответом. Это очень распространенная вещь, но среда размещения ASP.NET плохо приспособлена для выполнения длительной работы.

Пожалуйста, поделитесь своими мыслями.


person Community    schedule 25.03.2010    source источник


Ответы (4)


Джон,

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

У нас были подобные ситуации в прошлом, и мы использовали решение, подобное тому, что вы описали. Таким образом, держите свою службу WCF в ASP.NET, используйте таблицу «Очередь» со службой Windows в качестве «QueueProcessor». Клиент должен опросить, чтобы узнать, выполнена ли работа (или использовать обмен сообщениями, чтобы уведомить клиента).

Мы использовали таблицу, содержащую процесс и информацию о нем (например, InvoicingRun). В этой таблице был статус (ожидание, выполнение, завершение, сбой). Клиент отправит новый InvoicingRun со статусом Pending. Служба Windows (процессор) будет опрашивать базу данных, чтобы получить любые запуски, которые находятся на стадии ожидания (вы также можете использовать уведомление SQL, чтобы вам не нужно было опрашивать. Если будет найден ожидающий запуск, он переместит его в состояние выполнения, выполните обработку, а затем переместите ее в завершенную/неудачную.

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

Если было несколько процессоров, то задание получал тот, кто первым переведет его в рабочее состояние. Этот метод можно использовать для предотвращения повторного запуска задания. Альтернативой является выбор, а затем обновление для запуска в рамках транзакции. Убедитесь, что любой из них находится за пределами более крупной транзакции. Пример (грубый) SQL:

UPDATE InvoicingRun
SET Status = 2 -- Running
WHERE ID = 1
    AND Status = 1 -- Pending

IF @@RowCount = 0
    SELECT Cast(0 as bit)
ELSE
    SELECT Cast(1 as bit)

Роб

person Community    schedule 25.03.2010
comment
Это вроде как очевидно, когда вы упоминаете об этом, не подумал об этом. Я мог бы, конечно, пометить строку как ожидающую обработки, как только я начну обработку, но до того, как я выполню какую-либо реальную работу. Но как предотвратить застревание строки в состоянии ожидания, если, например. БД выходит из строя во время выполнения? (это очень маловероятно, но я хочу быть тщательным) - person John Leidegren; 26.03.2010
comment
Ну, возможно, он застрянет в рабочем состоянии. Я думаю, вам нужно, чтобы администратор-человек вернул его (либо через интерфейс, либо непосредственно в БД), как только проблема, вызвавшая сбой, была решена. Это связано с тем, что будет трудно сказать, работает он или нет. Если это не вариант, добавьте сторожевой таймер, который сбрасывает его через определенное время (когда вы уверены, что процесс завершился неудачно). Может быть трудно определить, каким должно быть это время. Последний вариант — сохранить транзакцию в этой строке, но тогда вы столкнетесь с проблемами одновременного доступа. - person Robert Wagner; 26.03.2010
comment
Джон, это одна из тех вещей, которые очевидны, если подумать. Описанный метод представляет собой параллелизм Mutex. - person Robert Wagner; 26.03.2010
comment
Комбинация двух наших подходов к SQL должна решить любые проблемы параллелизма, и вам, вероятно, потребуется, чтобы кто-то или что-то периодически проверяло, работает ли служба должным образом. - person John Leidegren; 26.03.2010
comment
Что нужно знать об уведомлении SQL, так это то, что оно было удалено из SQL Server 2008. Кроме того, структура ввода-вывода за таблицами делает их плохо подходящими для реализации очередей — это связано с поведением кластеризованного индекса первичных ключей, что приводит к реструктуризации БД. расположение данных по мере расширения и сжатия очереди. - person Udi Dahan; 25.06.2010
comment
С введением AzureWebJobs теперь вы можете это сделать. Смотрите мой ответ для более подробной информации. Рабочая роль Azure была бы еще более надежной. - person RickAndMSFT; 21.01.2014

Взгляните на NServiceBus.

NServiceBus — это коммуникационная платформа с открытым исходным кодом для .NET со встроенной поддержкой публикации/подписки и длительных процессов.

Это технология, основанная на MSMQ, что означает, что ваши сообщения не теряются, поскольку они сохраняются на диске. Тем не менее, фреймворк обладает впечатляющей производительностью и интуитивно понятным API.

person Community    schedule 25.03.2010
comment
Я этого не делал, но мог бы и сделать, потому что это немного не по теме. NServiceBus, по-видимому, является средой передачи сообщений для создания распределенных приложений. На самом деле это не имеет ничего общего с длительными процессами. Он может использоваться для передачи данных (отправки сообщений), но на самом деле он ничего не говорит о том, чтобы одновременно полагаться на поведение/инструкции, и из-за этого он как бы теряет свою значимость. Какую проблему решает NServiceBus, которую не решает WCF? - person John Leidegren; 26.03.2010
comment
Он поддерживает длительные рабочие процессы через SAGAS: nservicebus.com/Sagas.aspx. Вы не получаете это из коробки с WCF - person Manu; 26.03.2010
comment
NServiceBus имеет встроенную интеграцию для задач асинхронных страниц ASP.NET для реализации долго работающих страниц, а в следующей версии (2.1) также поддерживает интеграцию MVC AsyncController. NServiceBus во многом поддерживает долговременные процессы, а также облегчает связь с этими процессами надежным и отказоустойчивым способом. Хотя вы можете настроить WCF для этого, вам нужно много знать о WCF, чтобы сделать это правильно, тогда как с NServiceBus все работает именно так по умолчанию. Еще одна вещь, которую WCF не дает вам, — это надежная балансировка нагрузки для MSMQ, которую дает NServiceBus. - person Udi Dahan; 25.06.2010

Думали об использовании Workflow Foundation вместо собственной реализации? Это также позволяет вам сохранять состояния. В этом случае задачи могут быть определены как рабочие процессы.

Просто некоторые мысли...

Майкл

person Community    schedule 25.03.2010
comment
Я нет, WWF кажется чем-то вроде большого конгломерата, который решает другие виды асинхронных бизнес-ориентированных задач. На самом деле речь идет о простом вычислении чисел в другом потоке, но при этом надежном. Я ценю предложение, хотя. - person John Leidegren; 26.03.2010

Используйте простую структуру фоновых задач/заданий, такую ​​как Hangfire, и примените эти принципы передовой практики к остальной части вашего решения. :

  • Делайте все действия как можно меньше; чтобы добиться этого, вы должны-
  • Разделите длительные задания на пакеты и поставьте их в очередь (в очередь Hangfire или на шину другого типа)
  • Убедитесь, что ваши небольшие задания (пакетные части длинных заданий) являются идемпотентными (имеют весь контекст, необходимый для запуска в любом порядке). Таким образом, вам не нужно использовать очередь, которая поддерживает последовательность; потому что тогда ты сможешь
  • Распараллеливайте выполнение заданий в очереди в зависимости от количества узлов в ферме веб-серверов. Вы даже можете контролировать, какой нагрузке подвергается ваша ферма (в качестве компромисса с обслуживанием веб-запросов). Это гарантирует, что вы выполните всю работу (все пакеты) как можно быстрее и эффективнее, не ставя под угрозу свой кластер из-за обслуживания веб-клиентов.
person Community    schedule 19.01.2017