Могу ли я использовать потоки для выполнения длительных заданий в IIS?


85

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

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

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


1
У вас есть более подробная информация о том, что необходимо обработать, и о вашей среде хостинга? Например, вы можете установить услугу?
senfo

Вы всегда можете использовать методы программирования Async и Await (Visual Studio 2012+). Намного чище, чем самостоятельное управление потоками.
SausageFingers

Ответы:


65

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

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

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

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

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

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

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

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


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

Да, здесь проверить это: professionalaspnet.com/archive/2007/09/02/... А вот нить о том , как Сообществе сервер обрабатывает то же самое: dev.communityserver.com/forums/t/459942.aspx
Bryan Батчелдер

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

1
Странно, что за него так много голосов. То, что это возможно, - одна из замечательных особенностей ASP.NET: все запросы обслуживаются в одном домене приложений вместе с любыми фоновыми потоками, которые вы можете создать. Ни одна из приведенных причин, почему это «плохая идея» не кажется мне убедительной. Да, домены приложений могут выйти из строя, но это вряд ли уникально для среды ASP.NET. Вы должны хорошо играть со своей средой хостинга (Google для HostingEnvironment.RegisterObject).
Джон

3
В .NET 4.5.2 добавлена ​​новая функция QueueBackgroundWorkItemдля простой регистрации фоновых задач. Возможно, вы захотите обновить свой ответ еще раз.
Скотт Чемберлен

39

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

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

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

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

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

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

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


Это круто. У меня есть задача, на выполнение которой требуется около 30 секунд. Идеально, если вам просто нужно отложить пул приложений на время, необходимое для выполнения работы.
Scuba Steve

1
Из .Net Framework 4.5.2 вы также можете использовать HostingEnvironment.QueueBackgroundWorkItem (Action <CancellationToken>)
Жерар Карбо,

По моим наблюдениям, кажется, что IIS в конечном итоге завершает работу ASP.NET Web API, который я использую, и не запускает его, пока не поступит новый запрос. Таким образом, в назначенное время, когда мой поток должен запустить приложение, может даже не работать. Я ошибаюсь в этом?
Давид Сопко

7

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


Ах, MSMQ - одна из моих давних любимых технологий. Спасибо за понимание и ссылку.
Frans

6

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


5

Здесь есть хорошая тема и пример кода: 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;
    }

5

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

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

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

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

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

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

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


2

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

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

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


2

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


2

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


1

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.