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

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

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

EDIT. Из ответов и комментариев я понимаю, что лучший способ сделать это - переместить длительную обработку за пределы IIS. Помимо всего прочего, это касается проблемы утилизации апдомен. На практике мне нужно получить версию 1 с земли в ограниченное время и работать в существующей структуре, поэтому хотелось бы избежать уровня сервиса, отсюда желание просто отключить поток внутри IIS. На практике "длительное время" здесь будет всего лишь несколько минут, а concurrency на сайте будет низким, так что все должно быть в порядке. Но следующей версии определенно потребуется разделить на отдельный уровень обслуживания.

Ответ 1

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

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

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

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

Опять же, это, как правило, плохая идея.

EDIT: Вот несколько примеров этой техники в действии:

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

EDIT (из далекого будущего) - В эти дни я бы использовал Hangfire.

Ответ 2

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

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

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

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

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

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

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

Ответ 3

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

Ответ 4

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

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

Ответ 6

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

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

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

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

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

Для более подробной информации о доступных вариантах можно узнать Скотта Гензельмана blog, который охватывает несколько вариантов обработки фоновых заданий в asp.net, (Он дал фальшивый обзор)

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

Ответ 7

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

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

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

Ответ 8

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

Ответ 9

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

Ответ 10

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