2016-08-12 6 views
5

मैं एक स्वयं के द्वारा होस्ट Owin पर्यावरण के भीतर एक ApiController में एक लंबा चल रहा कार्य (जैसे कि 4-5 मिनट) को चलाने के लिए चाहते हैं। हालांकि मैं एक प्रतिक्रिया (जैसे ही मैं लंबे समय से चल रहा है काम शुरू कर दिया) यह खत्म करने के लिए इंतजार किए बिना उस कार्य को शुरू करने के बाद वापस भेजना चाहते हैं। इस लंबे समय तक चलने वाले कार्य में HTTP के साथ कुछ लेना देना नहीं है और अनुक्रमिक रूप से कुछ विधियों को चलाता है जो बहुत अधिक समय ले सकते हैं।ApiController में दीर्घ परिचालन कार्य (वेबएपीआई, का उपयोग कर स्वयं के द्वारा होस्ट Owin)

मैं this ब्लॉग पोस्ट पर एक नजर है और QueueBackgroundWorkItem को एक कोशिश देने का फैसला किया। हालांकि, मुझे यकीन है कि अगर यह पर्यावरण या उसका उपयोग करने के लिए आवश्यक Owin एक स्वयं की मेजबानी (कंसोल आवेदन) में इस पद्धति का उपयोग करना संभव है नहीं कर रहा हूँ। एक स्वयं की मेजबानी की सांत्वना आवेदन मुझे लगता है, आवेदन ही अनुरोध और एक ही AppDomain में चलने सभी अनुरोध प्रबंधन में (अनुप्रयोगों डिफ़ॉल्ट AppDomain, हम किसी भी नए AppDomain बनाने नहीं है), तो मैं बस में एक लंबा चल रहा है काम चला सकते हैं हो सकता है आग लगाना और भूलना फैशन, कुछ विशेष किए बिना?

वैसे भी, जब मैं QueueBackgroundWorkItem उपयोग करते हैं, मैं हमेशा त्रुटि मिलती है:

<Error> 
<Message>An error has occurred.</Message> 
<ExceptionMessage> 
Operation is not valid due to the current state of the object. 
</ExceptionMessage> 
<ExceptionType>System.InvalidOperationException</ExceptionType> 
<StackTrace> 
at System.Web.Hosting.HostingEnvironment.QueueBackgroundWorkItem(Func`2 workItem) at BenchMarkService.SmokeTestController.IsItWorking() in C:\Devel\Code\Projects\BenchMarkService\BenchMarkService\SmokeTestController.cs:line 18 at lambda_method(Closure , Object , Object[]) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken) --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext() 
</StackTrace> 
</Error> 

इसके अलावा, मैं इतने पर this सवाल पाया और ईमानदार यह एक ही तरीका है कि प्राप्त करने के लिए के रूप में मेरे लिए भ्रामक एक छोटा सा लगता है होना करने के लिए IRegisteredObject है या नहीं?

मैं सिर्फ एक स्वयं के द्वारा होस्ट आवेदन पत्र में एक लंबी चलने वाली कार्य चलाने के लिए कोशिश कर रहा हूँ और मुझे लगता है कि के बारे में किसी भी विचार की सराहना करते हैं। लगभग सभी संसाधन, मुझे मिले प्रश्न एएसपीनेट पर आधारित हैं और मुझे यकीन नहीं है कि कहां से शुरू करना है।

+0

क्या यह कार्य (डेटाबेस में) कतारबद्ध करने का विकल्प नहीं है और कुछ सेवा इसे संभालने दें? –

+0

हैंगफायर (https://www.hangfire.io/) कुछ ऐसा ही करता है जहां तक ​​मुझे पता है।हालांकि, मैं इस सवाल से थोड़ा अलग मानता हूं। – Deniz

उत्तर

2

स्व की मेजबानी Owin प्रयोगों को विशिष्ट नियमित सांत्वना अनुप्रयोगों हैं, इसलिए आप उसी तरह से कुछ देर तक चल रहा कार्य आप क्या करेंगे कि एक सांत्वना आवेदन में, उदाहरण के लिए बंद स्पिन कर सकते हैं:

  • Task.Run
  • ThreadPool.QueueUserWorkItem
  • new Thread(...).Start()

आईआईएस में की मेजबानी ASP.NET अनुप्रयोगों यह ऐसी विधियों का उपयोग करने के लिए उचित नहीं है क्योंकि एप्लिकेशन पूल आमतौर पर पुनर्नवीनीकरण होते हैं, इसलिए आपका एप्लिकेशन बंद हो जाता है और अक्सर बार-बार शुरू होता है। ऐसे मामले में आपका पृष्ठभूमि कार्य निरस्त कर दिया जाएगा। को रोकने के लिए (या स्थगित) है कि में, QueueBackgroundWorkItem तरह एपीआई पेश किया गया है।

हालांकि, क्योंकि आप स्वयं-होस्ट किए गए हैं और आईआईएस में नहीं चलते हैं, आप बस ऊपर सूचीबद्ध एपीआई का उपयोग कर सकते हैं।

2

आपको नियंत्रक के बाहर कुछ करने के लिए एक कार्य जोड़ने के लिए एक तंत्र प्रदान करने की आवश्यकता है।

आम तौर पर मैं ऐप में वास्तविक होस्ट के लिए ओविन का उपयोग करता हूं, इसलिए मुझे पता चला कि मैं "होस्टेड प्रक्रियाओं" का उपयोग कर सकता हूं लेकिन एक कंसोल ऐप में यह बहुत आसान होने की संभावना है।

सबसे स्पष्ट दृष्टिकोण है कि मन में आता है वैश्विक वस्तु/सिंगलटन कि आपके डि ढांचे जानता है के बारे में सुनिश्चित हो सकता है किसी प्रकार का में पारित करने के लिए है हमेशा

public class FooController : ApiController 
{ 
    ITaskRunner runner; 

    public FooController(ITaskRunner runner) { this.runner = runner; } 

    Public IActionResult DoStuff() { 
     runner.AddTask(() => { Stuff(); }); 
     return Ok(); 
    } 
} 
एक "नौकरी के लिए कंटेनर" के रूप में एक ही वस्तु है

कार्य धावक कार्य के चारों ओर एक साधारण रैपर से थोड़ा अधिक होने से नौकरी कर सकता है।यदि आप चाहते थे तो चलाएं(), लेकिन उस हुक को वहां और पास करने का मतलब है कि अनुरोध के बाद "संभाला गया" और नियंत्रक साफ हो जाता है, कार्य अभी भी "दायरे में" माना जाता है, इसलिए एप्लिकेशन इसे संसाधित करना जारी रख सकता है इसे साफ करने का प्रयास कर रहा है।

2

मैं युद्ध के जवाब पर टिप्पणी करना चाहता था, लेकिन मेरे अपने प्रश्न का उत्तर देना लंबे स्पष्टीकरण के लिए बेहतर प्रतीत होता है। यह एक पूरा जवाब नहीं हो सकता है, क्षमा करें।

युद्ध का समाधान इस सुविधा को लागू करने का एक संभावित तरीका है और मैंने ऐसा कुछ किया। असल में, एक कार्य स्टोर बनाएं और जब भी कोई नया कार्य निकाल दिया जाता है या पूरा किया जाता है तो इस कार्य को कार्य स्टोर में जोड़ें/हटा दें। हालांकि, मैं कुछ मुद्दों का उल्लेख करना चाहता हूं, क्योंकि मुझे विश्वास है कि यह उतना आसान नहीं है जितना।

1) मैं सिंगलटन पैटर्न को लागू करने के लिए एक निर्भरता इंजेक्शन ढांचे का उपयोग करने के साथ सहमत हूं। मैंने ऐसा करने के लिए ऑटोफैक की 'सिंगल इंस्टेंस()' विधि का उपयोग किया। हालांकि, जैसा कि आप इंटरनेट पर कई उत्तरों और संसाधनों में देख सकते हैं, सिंगलटन पैटर्न लोकप्रिय पैटर्न नहीं है हालांकि कभी-कभी अनिवार्य लगता है।

2) आपका भंडार थ्रेड-सुरक्षित होना चाहिए, इसलिए उस कार्य स्टोर से कार्यों को जोड़ना/निकालना थ्रेड-सुरक्षित होना चाहिए। आप एक समवर्ती डेटा संरचना जैसे लॉकिंग के बजाय 'ConcurrentDictionary' का उपयोग कर सकते हैं (जो सीपीयू समय के मामले में एक महंगा ऑपरेशन है)।

3) आप अपने async के लिए CancellationToken का उपयोग करने पर विचार कर सकते हैं। संचालन। यह बहुत संभव है कि आपका एप्लिकेशन उपयोगकर्ता द्वारा बंद किया जा सकता है या अपवाद जिसे रनटाइम के दौरान किया जा सकता है। लंबे समय तक चलने वाले कार्यों को शानदार शट डाउन/रीस्टार्ट ऑपरेशंस के लिए बाधा हो सकती है, खासकर यदि आपके पास खोने के लिए संवेदनशील डेटा है और विभिन्न संसाधनों का उपयोग करें जैसे कि उस मामले में ठीक से बंद हो सकता है। हालांकि async। जब भी आप टोकन का उपयोग करके कार्य को रद्द करने का प्रयास करते हैं, तो विधियों को तत्काल रद्द नहीं किया जा सकता है, फिर भी जब भी आवश्यक हो, अपने लंबे समय तक चलने वाले कार्यों को रोकने/रद्द करने के लिए रद्द करना टोकन या इसी तरह के तंत्र को आज़माने के लायक है।

4) बस अपने डेटा स्टोर में एक नया कार्य जोड़ना पर्याप्त नहीं है, आपने सफलतापूर्वक या नहीं होने पर भी कार्य को हटा दिया है। मैंने एक ऐसी घटना को फायर करने की कोशिश की जो कार्य को पूरा करने का संकेत देता है और फिर मैंने इस कार्य को कार्य स्टोर से हटा दिया। हालांकि, मैं इससे खुश नहीं हूं क्योंकि एक घटना को फायर करना और फिर कार्य को पूरा करने के लिए इस घटना के लिए एक विधि को बाध्य करना टीपीएल में निरंतरता की तरह कम या कम है। यह पहिया को फिर से शुरू करने जैसा है और घटनाएं बहुसंख्यक वातावरण में स्नीकी समस्याओं का कारण बन सकती हैं।

उम्मीद है कि इससे मदद मिलती है। मैं कोड पोस्ट करने के बजाय कुछ अनुभव साझा करना पसंद करता हूं, क्योंकि मुझे विश्वास नहीं है कि इस समस्या का मेरा अंतिम समाधान है। युद्ध की प्रतिक्रिया एक मोटा विचार देती है, लेकिन आपको उत्पादन तैयार प्रणाली में ऐसा करने से पहले कई मुद्दों पर विचार करने की आवश्यकता है।

संपादित करें: लंबे समय तक चलने वाले कार्यों के लिए आपको this धागा दिखाई दे सकता है। थ्रेड पूल का प्रबंधन करने के लिए यह एक अच्छा अभ्यास है।

+0

ये मेरे विचार बिल्कुल ... मैं अपने उत्तर को बहुत अधिक पृष्ठभूमि जानकारी के साथ छेड़छाड़ नहीं करने की कोशिश कर रहा था जो आपके कार्यान्वयन के बारे में धारणाएं कर सकता है या नहीं। एक पूर्ण समाधान के लिए आप अपने कोडबेस के बाकी हिस्सों में पैटर्न/कोडिंग मानकों को पूरा करने के पक्ष में काफी सरल कुछ करना चाहते हैं। थ्रेडिंग चिंताओं के लिए, अच्छी तरह से आपके डेटा लेयर/बिजनेस लॉजिक को इस स्तर पर संभालना चाहिए, इसलिए मैं धागे/कार्यों को लात मारने के बारे में चिंतित नहीं हूं। मेरा 2 पी ... खुशी है कि आप इसे हल किया हालांकि :) – War

3

यह हैगफ़ीयर को बनाने के लिए बनाया गया था (https://www.hangfire.io/)।

आग-और-भूल नौकरी की तरह लगता है।

var jobId = BackgroundJob.Enqueue(
    () => Console.WriteLine("Fire-and-forget!")); 
2

पुशस्ट्रीम सामग्री वह उत्तर हो सकता है जिसे आप ढूंढ रहे हैं। पुशस्ट्रीम सामग्री प्रतिक्रिया स्ट्रीम करने में मदद करता है। कार्यान्वयन के बारे में कुछ विचार पाने के लिए निम्नलिखित ब्लॉग पोस्ट को देख रहे हैं। STREAMING DATA WITH ASP .NET WEB API AND PUSHCONTENTSTREAM

संबंधित मुद्दे