IIS'de uzun süreli işleri gerçekleştirmek için iş parçacıkları kullanabilir miyim?


85

Bir ASP.Net uygulamasında, kullanıcı web sayfasındaki bir düğmeyi tıklatır ve bu, olay işleyicisi aracılığıyla sunucuda bir nesnenin örneğini oluşturur ve nesne üzerinde bir yöntem çağırır. Yöntem, bir şeyler yapmak için harici bir sisteme geçer ve bu biraz zaman alabilir. Yani, yapmak istediğim şey, bu yöntem çağrısını başka bir iş parçacığında çalıştırmak, böylece "İsteğiniz gönderildi" ile kullanıcıya kontrolü geri verebilirim. Bunu ateşle ve unut olarak yapmaktan oldukça mutluyum, ancak kullanıcının statü için nesneyi sorgulamaya devam etmesi daha da güzel olurdu.

Bilmediğim şey, IIS, kullanıcı oturumu sona erse bile iş parçacığımın çalışmaya devam etmesine izin verip vermediğidir. Düşünün, kullanıcı olayı tetikliyor ve biz de nesneyi sunucuda başlatıyoruz ve yöntemi yeni bir iş parçacığında çalıştırıyoruz. Kullanıcı, "İsteğiniz gönderildi" mesajından memnun kalır ve tarayıcısını kapatır. Sonunda, bu kullanıcı oturumu IIS'de zaman aşımına uğrayacaktır, ancak iş parçacığı hala çalışıyor ve çalışıyor olabilir. IIS iş parçacığının çalışmaya devam etmesine izin verecek mi yoksa kullanıcı oturumu sona erdiğinde onu öldürüp nesneyi atacak mı?

DÜZENLEME: Cevaplardan ve yorumlardan, bunu yapmanın en iyi yolunun uzun süren işlemleri IIS dışına taşımak olduğunu anlıyorum. Her şeyden ayrı olarak, bu uygulama alanı geri dönüşüm problemiyle ilgilenir. Uygulamada, sürüm 1'i sınırlı bir süre içinde sıfıra indirmem gerekiyor ve mevcut bir çerçeve içinde çalışmam gerekiyor, bu nedenle hizmet katmanından kaçınmak istiyorum, dolayısıyla IIS içindeki iş parçacığını ateşleme arzusu. Pratikte, burada "uzun çalışma" sadece birkaç dakika sürecek ve web sitesindeki eşzamanlılık düşük olacak, bu yüzden sorun olmayacaktır. Ancak, bir sonraki sürümün kesinlikle ayrı bir hizmet katmanına bölünmesi gerekecek.


1
Nelerin işlenmesi gerektiği ve barındırma ortamınız hakkında daha fazla ayrıntı var mı? Örneğin, bir hizmet kurabiliyor musunuz?
senfo

Her zaman Async ve Await programlama yöntemlerini (Visual Studio 2012+) kullanabilirsiniz. Konuları kendiniz yönetmekten çok daha temiz.
SausageFingers

Yanıtlar:


65

İstediğinizi başarabilirsiniz, ancak bu genellikle kötü bir fikirdir. Bazı ASP.NET blog ve CMS motorları bu yaklaşımı benimser, çünkü paylaşılan bir barındırma sistemine kurulabilir olmak ve yüklenmesi gereken bir Windows hizmetine bağımlı olmak istemezler. Tipik olarak, uygulama başladığında Global.asax'ta uzun süre çalışan bir iş parçacığı başlatırlar ve bu iş parçacığı işleminin görevleri sıraya koymasını sağlarlar.

İstekleri işlemek için IIS / ASP.NET tarafından sağlanan kaynakları azaltmanın yanı sıra, AppDomain geri dönüştürüldüğünde öldürülen iş parçacığı ile ilgili sorunlar yaşarsınız ve daha sonra görev yayındayken görevin kalıcılığıyla uğraşmanız gerekir. ve AppDomain geri geldiğinde işi yedeklemeye başlar.

Çoğu durumda, AppDomain'in varsayılan bir aralıkta ve ayrıca web.config'i vb. Güncellerseniz otomatik olarak geri dönüştürüldüğünü unutmayın.

Kesilen iş parçacığınızın kalıcılığını ve işlemsel yönlerini herhangi bir zamanda halledebilirseniz, sitenizde belirli aralıklarla talepte bulunan bazı harici işlemlere sahip olarak AppDomain geri dönüşümünün etrafından dolaşabilirsiniz - böylece site geri dönüştürülürse sizi X dakika içinde otomatik olarak yeniden başlatılması garantilidir.

Yine, bu genellikle kötü bir fikirdir.

DÜZENLEME: İşte bu tekniğin uygulamadaki bazı örnekleri:

Topluluk Sunucusu: Programlanmış Aralıklarda Kodu Çalıştırmak İçin Windows Hizmetlerini Kullanmak ve Arka Plan İş Parçacığını Kullanma Web Sitesi İlk Başladığında Arka Plan İş Parçacığı Oluşturma

DÜZENLE (uzak gelecekten) - Bugünlerde Hangfire kullanacağım .


1
Teşekkürler, bu anlayışlı. Geri dönüşüm kesin bir katildir ve söylediklerinizden , bunu zor ve hızlı bir şey olarak yapabilirim ama tehlikeli olduğunu anlıyorum.
Frans


Benim durumumda, IIS'ye asla geri dönüştürmemesini ve siteyi asla boşa çıkarmamasını söyleyebildim. Bu, bu varsayım altında çalışabilmem ve sitenin yalnızca dağıtım sırasında ve planlanan bakım gerçekleştiğinde geri dönüştürülmesini sağladı. Sadece yönetici tipi bir site yaptığım için, bu benim için mükemmel oldu.
Brett

1
Bunun çok fazla olumlu oyu olması tuhaf. Bu şeyin mümkün olması, ASP.NET ile ilgili en güzel şeylerden biridir: Tüm istekler, oluşturabileceğiniz herhangi bir arka plan iş parçacığı ile birlikte aynı AppDomain içinde sunulur. Bunun neden "kötü bir fikir" olduğuna dair verilen nedenlerin hiçbiri beni ikna edici bulmuyor. AppDomains düşebilir, evet - ancak bu ASP.NET ortamına pek de benzersiz değildir. Barındırma ortamınızla iyi oynamalısınız (google for HostingEnvironment.RegisterObject).
John

3
.NET 4.5.2, QueueBackgroundWorkItemarka plan görevlerini kolayca kaydetmek için yeni bir özellik ekledi , cevabınızı yeniden güncellemek isteyebilirsiniz.
Scott Chamberlain

40

Kabul edilen cevaba katılmıyorum.

Bir arka plan iş parçacığı (veya başlatılan bir görev Task.Factory.StartNew) kullanmak ASP.NET'te iyidir. Tüm barındırma ortamlarında olduğu gibi, kapatmayı yöneten tesisleri anlamak ve bunlarla işbirliği yapmak isteyebilirsiniz.

ASP.NET'te, HostingEnvironment.RegisterObjectyöntemi kullanarak kapatma sırasında düzgün bir şekilde durması gereken işi kaydedebilirsiniz . Bkz bu yazıyı ve bir tartışma için bir yorum.

(Gerard'ın yorumunda işaret ettiği gibi, artık arka plan öğesinin üzerinde çalışması için bir zamanlayıcı kaydettirme HostingEnvironment.QueueBackgroundWorkItemçağrısı da var RegisterObject. Genel olarak yeni yöntem, göreve dayalı olduğu için daha güzel.)

Kötü bir fikir olduğunu sık sık duyduğunuz genel temaya gelince, bir Windows hizmetini (veya başka bir tür ekstra işlem uygulamasını) dağıtmanın alternatifini düşünün:

  • Web dağıtımı ile artık önemsiz dağıtım yok
  • Yalnızca Azure Web Sitelerinde dağıtılamaz
  • Arka plan görevinin niteliğine bağlı olarak, süreçler muhtemelen iletişim kurmak zorunda kalacaktır. Bu, bir tür IPC veya hizmetin ortak bir veritabanına erişmesi gerektiği anlamına gelir.

Ayrıca, bazı gelişmiş senaryoların, isteklerle aynı adres alanında çalışması için arka plan iş parçacığına bile ihtiyaç duyabileceğini unutmayın. ASP.NET'in bunu .NET aracılığıyla mümkün hale gelen büyük bir avantaj olarak yapabileceğini görüyorum.


Bu harika. Tamamlanması yaklaşık 30 saniye süren bir görevim var. İşi tamamlamak için uygulama havuzunu yeterince geciktirmeniz gerekiyorsa mükemmeldir.
Scuba Steve

1
.Net Framework 4.5.2'den ayrıca HostingEnvironment.QueueBackgroundWorkItem (Action <CancellationToken>)
Gerard Carbó

Gözlemlerime göre, IIS sonunda çalıştığım ASP.NET Web API'sini kapatıyor ve yeni bir istek gelene kadar onu yeniden başlatmıyor gibi görünüyor. Bu nedenle, iş parçacığımın uygulamayı başlatması gerektiği belirlenen zamanda koşmuyor bile. Bu konuda yanılıyor muyum?
David Sopko

7

Bu görev için IIS iş parçacığı havuzundan bir iş parçacığı kullanmak istemezsiniz çünkü bu iş parçacığını gelecekteki istekleri işleyemez hale getirir. ASP.NET 2.0'da Eşzamansız Sayfalara bakabilirsiniz , ancak bu da gerçekten doğru yanıt olmaz. Bunun yerine, yararlanabileceğiniz gibi görünen şey Microsoft Message Queuing'e bakmaktır . Esasen, görev ayrıntılarını kuyruğa eklersiniz ve başka bir arka plan işlemi (muhtemelen bir Windows Hizmeti) bu görevi yerine getirmekten sorumlu olur. Ancak sonuç olarak, arka plan süreci tamamen IIS'den izole edilmiştir.


Ah, MSMQ - uzun vadeli favori teknolojilerimden biri. Görüş ve bağlantı için teşekkürler.
Frans

6

Bu tür gereksinimler için HangFire'ı kullanmanızı öneririm . Güzel bir ateş ve unut motoru arka planda çalışır, farklı mimariyi destekler, kalıcı depolama ile desteklendiği için güvenilirdir.


5

Burada iyi bir iş parçacığı ve örnek kod var: http://forums.asp.net/t/1534903.aspx?PageIndex=2

Uygulama havuzunu canlı tutmaya yardımcı olmak için web sitemdeki bir canlı tutma sayfasını ileti dizisinden arama fikrini bile oynadım. Bu yöntemi kullanıyorsanız, gerçekten iyi bir kurtarma işlemine ihtiyacınız olduğunu unutmayın, çünkü uygulama her an geri dönüşebilir. Birçoğunun da bahsettiği gibi, diğer hizmet seçeneklerine erişiminiz varsa, bu doğru yaklaşım değildir, ancak paylaşımlı barındırma için bu, tek seçeneklerinizden biri olabilir.

Uygulama havuzunu canlı tutmaya yardımcı olmak için iş parçacığı işlenirken kendi sitenize bir istekte bulunabilirsiniz. Bu, işleminiz uzun sürerse uygulama havuzunu canlı tutmanıza yardımcı olabilir.

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

Bu yola başladık ve aslında uygulamamız tek bir sunucudayken iyi çalıştı. Birden fazla makineye ölçeklendirmek istediğimizde (veya bir web gareninde birden fazla w3wp kullanmak), bir iş kuyruğunu, hata işlemeyi, yeniden denemeleri ve yalnızca bir makineyi garantilemek için doğru kilitlemenin karmaşık sorununu nasıl yöneteceğimizi yeniden değerlendirmeli ve incelemeliydik. sunucu bir sonraki öğeyi alır.

... arka plan işleme motorları yazma işinde olmadığımızı fark ettik, bu yüzden mevcut çözümleri aradık ve harika OSS projesi hangfire'ı kullanarak indik

Sergey Odinokov, başlaması gerçekten kolay olan gerçek bir mücevher yarattı ve işin nasıl sürdürüldüğü ve sıraya alındığının arka ucunu değiştirmenize izin veriyor. Hangfire, arka planda iş parçacıkları kullanır, ancak işleri devam ettirir, yeniden denemeleri gerçekleştirir ve size iş kuyruğunu görmenizi sağlar. Öyleyse hangfire işleri sağlamdır ve geri dönüştürülen uygulama alanlarının tüm belirsizliklerinden kurtulur.

Temel kurulumu, depolama olarak sql sunucusunu kullanır, ancak ölçekleme zamanı geldiğinde Redis veya MSMQ ile değiştirebilirsiniz. Ayrıca tüm işleri ve durumlarını görselleştirmek ve ayrıca işleri yeniden sıraya koymanıza olanak tanıyan mükemmel bir kullanıcı arayüzüne sahiptir.

Demek istediğim, bir arka plan iş parçacığında istediğinizi yapmak tamamen mümkün olsa da, onu ölçeklenebilir ve sağlam kılmak için çok fazla çalışma var. Basit iş yükleri için sorun değil, ancak işler daha karmaşık hale geldiğinde bu çabadan geçmek yerine amaca yönelik oluşturulmuş bir kitaplık kullanmayı tercih ederim.

Mevcut seçenekler hakkında daha fazla perspektif için, asp.net'teki arka plan işlerini ele almak için birkaç seçeneği kapsayan Scott Hanselman'ın bloguna bakın . (Hangfire'a parlak bir inceleme yaptı)

Ayrıca John tarafından atıfta bulunulduğu üzere Phil Haack'ın okumaya değer blog yaklaşımı sorunlu nedenine ve AppDomain nasıl iş parçacığı üzerinde incelikle durdurma çalışması için kaldırıldığında.


2

Bu görevi yapmak için bir Windows hizmeti oluşturabilir misiniz? Ardından, eylemi yapmak üzere Windows Hizmetini çağırmak için Web Sunucusundan .NET uzaktan erişimini kullanın. Eğer durum buysa ben de öyle yapardım.

Bu, IIS üzerinde geçiş yapma ihtiyacını ortadan kaldıracak ve işlem gücünün bir kısmını sınırlayacaktır.

Aksi takdirde, işlem tamamlanırken kullanıcıyı orada oturmaya zorlardım. Bu şekilde tamamlandığından ve IIS tarafından öldürülmediğinden emin olursunuz.


2

IIS'de uzun süreli çalışmaları barındırmanın desteklenen bir yolu var gibi görünüyor. İş Akışı Hizmetleri , özellikle Windows Server AppFabric ile birlikte bunun için tasarlanmış görünüyor . Tasarım, uzun süreli çalışmanın otomatik kalıcılığını ve yeniden başlamasını destekleyerek uygulama havuzu geri dönüşümüne izin verir.


2

Görevleri arka planda çalıştırabilirsiniz ve istek sona erdikten sonra bile tamamlanacaktır. Yakalanmamış bir istisnanın fırlatılmasına izin vermeyin . Normalde her zaman istisnalarınızı atmak istersiniz. Yeni bir iş parçacığına bir istisna atılırsa, IIS çalışan işlemini (w3wp.exe) çöker çünkü artık isteğin bağlamında değilsiniz. Bu ayrıca, kullanıyorsanız, işlem içi bellek destekli oturumlara ek olarak çalıştırdığınız diğer arka plan görevlerini de öldürecektir. Bunu teşhis etmek zor, bu yüzden uygulama cesareti kırılıyor.


1

Zaman uyumsuz görevleri çalıştırmak için bir vekil işlem oluşturun; bir Windows hizmeti olmak zorunda değildir (ancak bu çoğu durumda en uygun yaklaşımdır. MSMQ öldürmenin çok üzerindedir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.