Могу ли я использовать потоки для выполнения длительных заданий в IIS?
В приложении ASP.Net пользователь нажимает кнопку на веб-странице, а затем создает экземпляр объекта на сервере через обработчик событий и вызывает метод для объекта. Метод уходит во внешнюю систему, чтобы делать вещи, и это может занять некоторое время. Итак, я хотел бы запустить этот вызов метода в другом потоке, чтобы я мог вернуть управление пользователю с помощью "Ваш запрос был отправлен". Я довольно счастлив сделать это как "забыл и забыл", хотя было бы еще лучше, если бы пользователь мог продолжать опрашивать объект на предмет статуса.
Что я не знаю, так это то, что IIS позволяет моему потоку продолжать работу, даже если сеанс пользователя истекает. Представьте, пользователь запускает событие, и мы создаем экземпляр объекта на сервере и запускаем метод в новом потоке. Пользователь доволен сообщением "Ваш запрос отправлен" и закрывает свой браузер. В конце концов, этот сеанс пользователей будет зависать в IIS, но поток все еще может работать и выполнять работу. Позволит ли IIS потоку продолжить работу или он уничтожит его и удалит объект после окончания сеанса пользователя?
РЕДАКТИРОВАТЬ: Из ответов и комментариев, я понимаю, что лучший способ сделать это, чтобы перенести длительную обработку за пределы IIS. Помимо всего прочего, это касается проблемы утилизации appdomain. На практике мне нужно получить версию 1 с нуля за ограниченное время и работать в существующей среде, поэтому я хотел бы избежать уровня обслуживания, а следовательно, и желания просто запустить поток внутри IIS. На практике "длительный запуск" здесь займет всего несколько минут, а уровень параллелизма на сайте будет низким, поэтому все должно быть в порядке. Но следующая версия определенно должна быть разделена на отдельный уровень сервиса.
10 ответов
Вы можете выполнить то, что вы хотите, но это, как правило, плохая идея. Некоторые движки ASP.NET для блогов и CMS используют этот подход, потому что они хотят, чтобы их можно было устанавливать в системе общего хостинга, а не зависели от службы Windows, которая должна быть установлена. Обычно они запускают длительный поток в Global.asax при запуске приложения, и этот процесс ставит задачи в очередь.
В дополнение к сокращению ресурсов, доступных IIS/ASP.NET для обработки запросов, у вас также есть проблемы с завершением потока при перезапуске домена приложения, а затем вам приходится иметь дело с постоянством задачи во время ее выполнения, так как а также возобновить работу, когда снова появится AppDomain.
Помните, что во многих случаях домен приложения перезапускается автоматически с интервалом по умолчанию, а также при обновлении файла web.config и т. Д.
Если вы можете в любое время справиться с постоянством и транзакционными аспектами уничтожения вашего потока, то вы можете обойти перезапуск AppDomain, имея некоторый внешний процесс, который через некоторое время отправляет запрос на ваш сайт, так что если сайт будет переработан, вы гарантированно, что он автоматически запускается снова в течение Х минут.
Опять же, это, как правило, плохая идея.
РЕДАКТИРОВАТЬ: Вот несколько примеров этой техники в действии:
Сервер совместной работы: использование служб Windows и фонового потока для выполнения кода с запланированным интервалом Создание фонового потока при первом запуске веб-сайта
РЕДАКТИРОВАТЬ (из далекого будущего) - В эти дни я бы использовал Hangfire.
Я не согласен с принятым ответом.
Использование фонового потока (или задачи, начатой с Task.Factory.StartNew
) хорошо в ASP.NET. Как и во всех средах хостинга, вы, возможно, захотите разобраться и сотрудничать со средствами, регулирующими завершение работы.
В ASP.NET вы можете зарегистрировать работу, для которой нужно аккуратно остановиться при выключении, используя HostingEnvironment.RegisterObject
метод. Смотрите эту статью и комментарии для обсуждения.
Что касается общей темы, которую вы часто слышите о том, что это плохая идея, рассмотрите альтернативу развертывания службы Windows (или другого вида внепроцессного приложения):
- Нет больше тривиального развертывания с веб-развертыванием
- Нельзя развертывать только на веб-сайтах Azure.
- В зависимости от характера фоновой задачи процессам, скорее всего, придется взаимодействовать. Это означает, что либо какой-либо форме IPC, либо службе потребуется доступ к общей базе данных.
Также обратите внимание, что в некоторых расширенных сценариях фоновый поток может даже работать в том же адресном пространстве, что и запросы. Я вижу тот факт, что ASP.NET может сделать это как большое преимущество, которое стало возможным благодаря.NET.
Я бы предложил использовать HangFire для таких требований. Это хороший механизм запуска и запуска, работающий в фоновом режиме, поддерживающий другую архитектуру, надежный, поскольку он поддерживается постоянным хранилищем
Вы не захотите использовать поток из пула потоков IIS для этой задачи, потому что он не сможет обрабатывать будущие запросы. Вы можете посмотреть на асинхронные страницы в ASP.NET 2.0, но на самом деле это тоже не будет правильным ответом. Вместо этого вы получите выгоду от изучения очереди сообщений Microsoft. По сути, вы добавляете детали задачи в очередь, а другой фоновый процесс (возможно, служба Windows) будет отвечать за выполнение этой задачи. Но суть в том, что фоновый процесс полностью изолирован от IIS.
Мы пошли по этому пути, и он действительно работал нормально, когда наше приложение было на одном сервере. Когда мы хотели масштабировать до нескольких машин (или использовать несколько w3wp в веб-гарнире), нам пришлось переоценить и посмотреть, как управлять рабочей очередью, обработкой ошибок, повторными попытками и сложной проблемой правильной блокировки, чтобы гарантировать только одну Сервер забирает следующий элемент.
... мы поняли, что не занимаемся написанием движков фоновой обработки, поэтому мы искали существующие решения и взялись за работу, используя потрясающий проект OSS Hangfire
Сергей Одиноков создал настоящую жемчужину, с которой действительно легко начать, и позволяет вам поменять бэкэнд того, как работа сохраняется и ставится в очередь. Hangfire использует фоновые потоки, но сохраняет задания, обрабатывает повторы и предоставляет видимость в рабочую очередь. Таким образом, рабочие места Hangfire надежны и переживают все капризы перерабатываемых доменов приложений и т. Д.
Его базовая настройка использует sql server в качестве хранилища, но вы можете поменяться на Redis или MSMQ, когда его время будет увеличиваться. Он также имеет отличный пользовательский интерфейс для визуализации всех заданий и их состояния, а также позволяет повторно ставить задания в очередь.
Я хочу сказать, что хотя в фоновом потоке вполне возможно делать то, что вы хотите, существует много работы, чтобы сделать его масштабируемым и устойчивым. Это хорошо для простых рабочих нагрузок, но когда все усложняется, я предпочитаю использовать специально созданную библиотеку, а не проходить через это усилие.
Чтобы узнать больше о доступных опциях, загляните в блог Скотта Хансельмана, в котором описаны некоторые варианты обработки фоновых заданий в asp.net. (Он дал светящийся обзор Hangfire)
Также, на что ссылается Джон, стоит прочитать блог Фила Хаака о том, почему такой подход проблематичен, и как изящно прекратить работу над потоком, когда appdomain выгружен.
Здесь есть хороший поток и пример кода: http://forums.asp.net/t/1534903.aspx?PageIndex=2
Я даже поиграл с идеей вызвать на своем веб-сайте страницу поддержки активности, чтобы помочь поддерживать пул приложений. Имейте в виду, что если вы используете этот метод, вам нужна действительно хорошая обработка восстановления, потому что приложение может перезапускаться в любое время. Как многие уже упоминали, это неправильный подход, если у вас есть доступ к другим вариантам обслуживания, но для общего хостинга это может быть одним из ваших единственных вариантов.
Чтобы поддержать пул приложений, вы можете сделать запрос на свой сайт во время обработки потока. Это может помочь сохранить пул приложений, если ваш процесс выполняется долго.
string tempStr = GetUrlPageSource("http://www.mysite.com/keepalive.aspx");
public static string GetUrlPageSource(string url)
{
string returnString = "";
try
{
Uri uri = new Uri(url);
if (uri.Scheme == Uri.UriSchemeHttp)
{
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri);
CookieContainer cookieJar = new CookieContainer();
req.CookieContainer = cookieJar;
//set the request timeout to 60 seconds
req.Timeout = 60000;
req.UserAgent = "MyAgent";
//we do not want to request a persistent connection
req.KeepAlive = false;
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
Stream stream = resp.GetResponseStream();
StreamReader sr = new StreamReader(stream);
returnString = sr.ReadToEnd();
sr.Close();
stream.Close();
resp.Close();
}
}
catch
{
returnString = "";
}
return returnString;
}
Вы можете запускать задачи в фоновом режиме, и они будут выполнены даже после завершения запроса. Не позволяйте выбрасывать неисследованное исключение. Обычно вы хотите всегда бросать свои исключения. Если в новом потоке возникнет исключение, то произойдет сбой рабочего процесса IIS - w3wp.exe, поскольку вы больше не находитесь в контексте запроса. Это также приведет к уничтожению любых других фоновых задач, которые вы выполняете, в дополнение к сеансам, поддерживаемым в оперативной памяти, если вы их используете. Это было бы трудно диагностировать, поэтому практика не рекомендуется.
Кажется, существует один поддерживаемый способ размещения длительной работы в IIS. Сервисы Workflow, кажется, предназначены для этого, особенно в сочетании с Windows Server AppFabric. Конструкция позволяет повторно использовать пул приложений, поддерживая автоматическое сохранение и возобновление длительной работы.
Можете ли вы создать службу Windows для выполнения этой задачи? Затем используйте удаленное взаимодействие.NET с веб-сервера для вызова службы Windows для выполнения действия? Если это так, то я бы так и сделал.
Это устранит необходимость ретрансляции на IIS и ограничит часть его вычислительной мощности.
Если нет, то я бы заставил пользователя сидеть там, пока процесс завершен. Таким образом вы гарантируете, что оно завершено и не уничтожено IIS.
Просто создайте суррогатный процесс для запуска асинхронных задач; это не обязательно должна быть служба Windows (хотя в большинстве случаев это более оптимальный подход. MSMQ - это слишком много.