Могу ли я использовать потоки для выполнения длительных заданий в IIS? - PullRequest
80 голосов
/ 11 февраля 2009

В приложении ASP.Net пользователь нажимает кнопку на веб-странице, а затем создает экземпляр объекта на сервере через обработчик событий и вызывает метод для объекта. Метод уходит во внешнюю систему, чтобы делать вещи, и это может занять некоторое время. Итак, что я хотел бы сделать, это запустить этот вызов метода в другом потоке, чтобы я мог вернуть управление пользователю с помощью «Ваш запрос был отправлен». Я довольно счастлив сделать это как «забыл и забыл», хотя было бы еще лучше, если бы пользователь мог продолжать опрашивать объект на предмет статуса.

Чего я не знаю, так это того, что IIS позволяет моему потоку продолжать работу, даже если сеанс пользователя истекает. Представьте, пользователь запускает событие, и мы создаем экземпляр объекта на сервере и запускаем метод в новом потоке. Пользователь доволен сообщением «Ваш запрос отправлен» и закрывает свой браузер. В конце концов, этот сеанс пользователей будет зависать в IIS, но поток все еще может работать и выполнять работу. Позволит ли IIS потоку продолжить работу или он уничтожит его и удалит объект после истечения сеанса пользователя?

РЕДАКТИРОВАТЬ: Из ответов и комментариев я понимаю, что лучший способ сделать это - переместить длительную обработку за пределы IIS. Помимо всего прочего, это касается проблемы утилизации appdomain. На практике мне нужно получить версию 1 с нуля за ограниченное время, и она должна работать в существующей среде, поэтому я хотел бы избежать уровня обслуживания, отсюда и желание просто запустить поток внутри IIS. На практике «длительный запуск» здесь займет всего несколько минут, а уровень параллелизма на сайте будет низким, поэтому все должно быть в порядке. Но в следующей версии определенно потребуется разделение на отдельный уровень обслуживания.

Ответы [ 10 ]

63 голосов
/ 12 февраля 2009

Вы можете выполнить то, что вы хотите, но обычно это плохая идея. Некоторые движки ASP.NET для блогов и CMS используют этот подход, потому что они хотят, чтобы их можно было устанавливать в системе общего хостинга, а не зависели от службы Windows, которую нужно установить. Обычно они запускают долго работающий поток в Global.asax при запуске приложения, и этот процесс ставит задачи в очередь.

В дополнение к сокращению ресурсов, доступных IIS / ASP.NET для обработки запросов, у вас также есть проблемы с завершением потока при перезапуске домена приложения, а затем вам приходится иметь дело с постоянством задачи, пока она находится в процессе. Полет, а также возобновление работы при восстановлении домена приложений.

Имейте в виду, что во многих случаях AppDomain автоматически перезагружается с интервалом по умолчанию, а также при обновлении web.config и т. Д.

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

Опять же, это обычно плохая идея.

РЕДАКТИРОВАТЬ: Вот несколько примеров этой техники в действии:

Сервер совместной работы: использование служб Windows и фонового потока для выполнения кода с запланированным интервалом Создание фоновой темы при первом запуске сайта

РЕДАКТИРОВАТЬ (из далекого будущего) - В эти дни я бы использовал Hangfire .

32 голосов
/ 15 сентября 2014

Я не согласен с принятым ответом.

Использование фонового потока (или задачи, начатой ​​с Task.Factory.StartNew) - это нормально в ASP.NET. Как и во всех средах хостинга, вы, возможно, захотите понять и сотрудничать со средствами, регулирующими отключение.

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

(Как указывает Джерард в своем комментарии, теперь есть также HostingEnvironment.QueueBackgroundWorkItem, который вызывает RegisterObject, чтобы зарегистрировать планировщик для фонового элемента для работы. В целом, новый метод лучше, так как он основан на задачах.)

Что касается общей темы, которую вы часто слышите о том, что это плохая идея, рассмотрите альтернативу развертывания службы Windows (или другого вида внепроцессного приложения):

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

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

7 голосов
/ 11 февраля 2009

Вы не захотите использовать поток из пула потоков IIS для этой задачи, потому что он не сможет обрабатывать будущие запросы. Вы можете посмотреть на Асинхронные страницы в ASP.NET 2.0 , но это также не будет правильным ответом. Вместо этого вы можете извлечь выгоду из Microsoft Message Queuing . По сути, вы добавляете детали задачи в очередь, а другой фоновый процесс (возможно, служба Windows) будет отвечать за выполнение этой задачи. Но суть в том, что фоновый процесс полностью изолирован от IIS.

6 голосов
/ 04 февраля 2016

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

5 голосов
/ 12 января 2011

Здесь есть хороший поток и пример кода: 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;
    }
4 голосов
/ 06 ноября 2014

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

... мы поняли, что мы не занимаемся написанием механизмов фоновой обработки, поэтому мы искали существующие решения и получили доступ к удивительному проекту OSS hangfire

Сергей Одиноков создал настоящую жемчужину, с которой действительно легко начать работу, и позволяет вам поменять бэкэнд того, как работа сохраняется и ставится в очередь. Hangfire использует фоновые потоки, но сохраняет задания, обрабатывает повторы и дает видимость рабочей очереди. Таким образом, рабочие места Hangfire надежны и выдерживают все капризы перерабатываемых доменов приложений и т. Д.

Базовая настройка использует сервер SQL в качестве хранилища, но вы можете поменять его на Redis или MSMQ, когда его время будет увеличиваться. Он также имеет отличный пользовательский интерфейс для визуализации всех заданий и их состояния, а также позволяет повторно ставить задания в очередь.

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

Чтобы узнать больше о доступных опциях, загляните в блог Скотта Хансельмана , в котором описаны несколько вариантов обработки фоновых заданий в asp.net. (Он дал светящийся обзор Hangfire)

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

2 голосов
/ 27 октября 2016

Вы можете запускать задачи в фоновом режиме, и они будут выполняться даже после завершения запроса. Не позволяйте выбрасывать необученное исключение . Обычно вы хотите всегда бросать свои исключения. Если в новом потоке возникнет исключение, то произойдет сбой рабочего процесса IIS - w3wp.exe , поскольку вы больше не находитесь в контексте запроса. Это также затем приведет к уничтожению любых других фоновых задач, которые вы выполняете в дополнение к сеансам, поддерживаемым в оперативной памяти, если вы их используете. Это было бы трудно диагностировать, поэтому практика не рекомендуется.

2 голосов
/ 05 октября 2012

Кажется, существует один поддерживаемый способ размещения длительной работы в IIS. Workflow Services , похоже, предназначены для этого, особенно в сочетании с Windows Server AppFabric . Конструкция позволяет повторно использовать пул приложений, поддерживая автоматическое сохранение и возобновление длительной работы.

2 голосов
/ 12 февраля 2009

Можете ли вы создать службу Windows для выполнения этой задачи? Затем используйте удаленное взаимодействие .NET с веб-сервера для вызова службы Windows для выполнения действия? Если это так, то я бы так и сделал.

Это исключит необходимость ретрансляции на IIS и ограничит часть его вычислительной мощности.

Если нет, то я бы заставил пользователя сидеть там, пока процесс завершен. Таким образом вы гарантируете, что оно завершено и не уничтожено IIS.

1 голос
/ 13 февраля 2009

Просто создайте суррогатный процесс для запуска асинхронных задач; это не обязательно должна быть служба Windows (хотя в большинстве случаев это более оптимальный подход. MSMQ - это слишком много.

...