Чи можу я використовувати потоки для виконання тривалих завдань у IIS?


85

У програмі ASP.Net користувач натискає кнопку на веб-сторінці, а потім створює екземпляр об’єкта на сервері через обробник подій і викликає метод на об’єкті. Метод переходить до зовнішньої системи, щоб робити речі, і це може зайняти деякий час. Отже, те, що я хотів би зробити, - це запустити цей виклик методу в іншому потоці, щоб я міг повернути користувачеві контроль за допомогою "Ваш запит подано". Я достатньо радий зробити це як «забути і забути», хоча було б ще приємніше, якби користувач міг продовжувати опитування об’єкта щодо статусу.

Я не знаю, чи IIS дозволяє моєму потоку продовжувати працювати, навіть якщо термін дії сеансу користувача закінчується. Уявіть, користувач запускає подію, і ми створюємо об’єкт на сервері та запускаємо метод у новому потоці. Користувач задоволений повідомленням "Ваш запит надіслано" і закриває свій браузер. Врешті-решт цей сеанс користувачів закінчиться в IIS, але потік може все ще працювати, виконуючи роботу. Чи дозволить IIS потоку продовжувати працювати, чи він уб’є його та розпорядиться об’єктом після закінчення сеансу користувача?

EDIT: З відповідей та коментарів я розумію, що найкращий спосіб зробити це - перенести тривалу обробку за межі IIS. Окрім усього іншого, це стосується проблеми переробки додатків доменів. На практиці мені потрібно випустити версію 1 з місця за обмежений час, і вона повинна працювати всередині існуючого фреймворку, тому хотіла б уникнути сервісного рівня, звідси бажання просто запускати потік всередині IIS. На практиці "тривалий час" тут буде лише кілька хвилин, а паралельність на веб-сайті буде низькою, тому це повинно бути нормально. Але наступної версії однозначно потрібно буде розділити на окремий сервісний рівень.


1
Чи є у вас додаткові відомості про те, що потрібно обробити, і про ваше середовище хостингу? Наприклад, чи можете ви встановити послугу?
senfo

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

Відповіді:


65

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

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

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

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

Знову ж таки, це, як правило, погана ідея.

EDIT: Ось кілька прикладів цієї техніки в дії:

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

РЕДАГУВАТИ (з далекого майбутнього) - У ці дні я б використовував Hangfire .


1
Дякую, це проникливо. Переробка є певним вбивцею, і з того, що ви кажете, я розумію, що я можу зробити це як важку справу, але це небезпечно.
Франс

Так, тут перевірте це: professionalaspnet.com/archive/2007/09/02/… І ось тема про те, як COmmunity Server обробляє те саме: dev.communityserver.com/forums/t/459942.aspx
Брайан

У моєму випадку я зміг просто сказати IIS ніколи не переробляти і ніколи не робити простою на сайті. Це зробило так, що я міг працювати за цим припущенням і що сайт буде перероблятися лише під час розгортання та щоразу, коли відбуватиметься планове технічне обслуговування. Оскільки я просто робив сайт типу адміністратора, це вдалося для мене ідеально.
Бретт

1
Химерно, що тут так багато голосів. Те, що це можливо, є однією з найцікавіших речей про ASP.NET: усі запити подаються в одному AppDomain разом із будь-якими фоновими потоками, які ви можете створити. Жодна з наведених причин, чому це «погана ідея», не здається мені переконливою. Так, AppDomains можуть падати, але це навряд чи є унікальним для середовища ASP.NET. Вам потрібно приємно пограти з вашим хостинговим середовищем (google for 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>)
Gerard

З моїх спостережень здається, що IIS врешті-решт вимикає веб-API ASP.NET, який я запускаю, і не запускає його, поки не надходить новий запит. Отже, у призначений час, коли мій потік повинен розпочати роботу програми, може навіть не бігати. Я помиляюся в цьому?
Девід Сопко

7

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


Ах, MSMQ - одна з моїх давно улюблених технологій. Дякую за розуміння та посилання.
Франс

6

Я б запропонував використовувати HangFire для таких вимог. Його приємний двигун "Вогонь і забудь" працює у фоновому режимі, підтримує різну архітектуру, надійний, оскільки він підтримується постійним зберіганням.


5

Тут є хороший потік та зразок коду тут: http://forums.asp.net/t/1534903.aspx?PageIndex=2

Я навіть грався з ідеєю викликати на своєму веб-сайті сторінку "Keep Live", щоб допомогти зберегти пул додатків. Майте на увазі, якщо ви використовуєте цей метод, вам потрібна справді хороша процедура відновлення, оскільки програма може перероблятись у будь-який час. Як багато хто згадував, це не правильний підхід, якщо у вас є доступ до інших варіантів послуг, але для спільного хостингу це може бути одним з ваших єдиних варіантів.

Щоб допомогти зберегти пул програм живим, ви можете зробити запит на власний сайт, поки обробляється потік. Це може допомогти зберегти пул програм, якщо ваш процес триває довго.

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 у веб-мережі), нам довелося переоцінити та розглянути, як керувати робочою чергою, обробкою помилок, повторними спробами та хитрою проблемою правильного блокування, щоб забезпечити лише одну сервер забирає наступний пункт.

... ми зрозуміли, що не займаємося написанням двигунів фонової обробки, тому ми шукали існуючі рішення, і ми опинились на місці завдяки використанню чудового вогню проекту OSS

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

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

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

Детальніше розглянути доступні варіанти можна у блозі Скотта Хензельмана, який охоплює кілька варіантів роботи з фоновими завданнями на asp.net. (Він дав багаття яскравий огляд)

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


2

Чи можете ви створити службу Windows для виконання цього завдання? Потім скористайтеся віддаленим .NET із веб-сервера, щоб зателефонувати службі Windows, щоб виконати дію? Якщо це так, це те, що я б зробив.

Це усуне необхідність ретрансляції на IIS і обмежить деяку його обчислювальну потужність.

Якщо ні, тоді я б змусив користувача сидіти там, поки процес буде закінчено. Таким чином ви гарантуєте, що його завершує і не вбиває IIS.


2

Здається, існує один із підтримуваних способів розміщення тривалої роботи в IIS. Служби робочого циклу, здається, розроблені для цього, особливо спільно з Windows Server AppFabric . Конструкція дозволяє переробляти пул додатків, підтримуючи автоматичне збереження та відновлення тривалої роботи.


2

Ви можете запускати завдання у фоновому режимі, і вони виконуватимуться навіть після закінчення запиту. Не дозволяйте кинути невпійманий виняток . Зазвичай ви хочете завжди кидати свої винятки. Якщо виняток буде додано до нового потоку, це призведе до аварійного завершення робочого процесу IIS - w3wp.exe , оскільки ви більше не перебуваєте в контексті запиту. Потім це також призведе до знищення будь-яких інших фонових завдань, які ви виконуєте на додаток до сеансів із підтримкою пам’яті в процесі, якщо ви їх використовуєте. Це важко діагностувати, тому практика не рекомендується.


1

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.