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


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

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

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

10 73

10 ответов:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

здесь есть хороший поток и пример кода:http://forums.asp.net/t/1534903.aspx?PageIndex=2

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

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

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;
    }

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

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

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

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

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

дополнительные взглянуть на имеющиеся варианты проверить блог который охватывает несколько вариантов обработки фоновых заданий в asp.net (он дал hangfire светящийся обзор)

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

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

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

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

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

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

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

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