2012-04-21 20 views
7

मुझे एक अनुप्रयोग सर्वर की ओर समानांतर अनुरोध करने के लिए HttpWebRequest का उपयोग करते समय एक थ्रॉटलिंग तंत्र (प्रति सेकंड अनुरोध) लागू करने की आवश्यकता है। मेरे सी # ऐप को रिमोट सर्वर पर प्रति सेकेंड 80 से अधिक अनुरोध जारी नहीं करना चाहिए। दूरस्थ सेवा प्रशासकों द्वारा सीमा को एक कठोर सीमा के रूप में नहीं बल्कि मेरे मंच और उनके बीच "एसएलए" के रूप में लगाया गया है।एक वेबसर्वर की ओर प्रति सेकंड HttpWebRequest की संख्या को सीमित करने के लिए कैसे?

मैं कैसे अनुरोध प्रति सेकंड की संख्या जब HttpWebRequest का उपयोग कर नियंत्रित कर सकते हैं?

उत्तर

3

मुझे एक ही समस्या थी और एक तैयार समाधान नहीं मिला, इसलिए मैंने एक बनाया, और यहां यह है। विचार BlockingCollection<T> का उपयोग उन वस्तुओं को जोड़ने के लिए करना है जिन्हें प्रोसेसिंग की आवश्यकता है और रेट-सीमित प्रोसेसर के साथ सदस्यता लेने के लिए प्रतिक्रियाशील एक्सटेंशन का उपयोग करें।

थ्रॉटल वर्ग this rate limiter

public static class BlockingCollectionExtensions 
{ 
    // TODO: devise a way to avoid problems if collection gets too big (produced faster than consumed) 
    public static IObservable<T> AsRateLimitedObservable<T>(this BlockingCollection<T> sequence, int items, TimeSpan timePeriod, CancellationToken producerToken) 
    { 
     Subject<T> subject = new Subject<T>(); 

     // this is a dummyToken just so we can recreate the TokenSource 
     // which we will pass the proxy class so it can cancel the task 
     // on disposal 
     CancellationToken dummyToken = new CancellationToken(); 
     CancellationTokenSource tokenSource = CancellationTokenSource.CreateLinkedTokenSource(producerToken, dummyToken); 

     var consumingTask = new Task(() => 
     { 
      using (var throttle = new Throttle(items, timePeriod)) 
      { 
       while (!sequence.IsCompleted) 
       { 
        try 
        { 
         T item = sequence.Take(producerToken); 
         throttle.WaitToProceed(); 
         try 
         { 
          subject.OnNext(item); 
         } 
         catch (Exception ex) 
         { 
          subject.OnError(ex); 
         } 
        } 
        catch (OperationCanceledException) 
        { 
         break; 
        } 
       } 
       subject.OnCompleted(); 
      } 
     }, TaskCreationOptions.LongRunning); 

     return new TaskAwareObservable<T>(subject, consumingTask, tokenSource); 
    } 

    private class TaskAwareObservable<T> : IObservable<T>, IDisposable 
    { 
     private readonly Task task; 
     private readonly Subject<T> subject; 
     private readonly CancellationTokenSource taskCancellationTokenSource; 

     public TaskAwareObservable(Subject<T> subject, Task task, CancellationTokenSource tokenSource) 
     { 
      this.task = task; 
      this.subject = subject; 
      this.taskCancellationTokenSource = tokenSource; 
     } 

     public IDisposable Subscribe(IObserver<T> observer) 
     { 
      var disposable = subject.Subscribe(observer); 
      if (task.Status == TaskStatus.Created) 
       task.Start(); 
      return disposable; 
     } 

     public void Dispose() 
     { 
      // cancel consumption and wait task to finish 
      taskCancellationTokenSource.Cancel(); 
      task.Wait(); 

      // dispose tokenSource and task 
      taskCancellationTokenSource.Dispose(); 
      task.Dispose(); 

      // dispose subject 
      subject.Dispose(); 
     } 
    } 
} 

यूनिट परीक्षण के नाम दिया गया संस्करण है:

class BlockCollectionExtensionsTest 
{ 
    [Fact] 
    public void AsRateLimitedObservable() 
    { 
     const int maxItems = 1; // fix this to 1 to ease testing 
     TimeSpan during = TimeSpan.FromSeconds(1); 

     // populate collection 
     int[] items = new[] { 1, 2, 3, 4 }; 
     BlockingCollection<int> collection = new BlockingCollection<int>(); 
     foreach (var i in items) collection.Add(i); 
     collection.CompleteAdding(); 

     IObservable<int> observable = collection.AsRateLimitedObservable(maxItems, during, CancellationToken.None); 
     BlockingCollection<int> processedItems = new BlockingCollection<int>(); 
     ManualResetEvent completed = new ManualResetEvent(false); 
     DateTime last = DateTime.UtcNow; 
     observable 
      // this is so we'll receive exceptions 
      .ObserveOn(new SynchronizationContext()) 
      .Subscribe(item => 
       { 
        if (item == 1) 
         last = DateTime.UtcNow; 
        else 
        { 
         TimeSpan diff = (DateTime.UtcNow - last); 
         last = DateTime.UtcNow; 

         Assert.InRange(diff.TotalMilliseconds, 
          during.TotalMilliseconds - 30, 
          during.TotalMilliseconds + 30); 
        } 
        processedItems.Add(item); 
       }, 
       () => completed.Set() 
      ); 
     completed.WaitOne(); 
     Assert.Equal(items, processedItems, new CollectionEqualityComparer<int>()); 
    } 
} 
+0

यूआरएल के साथ कुछ बुरा हुआ –

-1

मेरे मूल पोस्ट ग्राहक व्यवहार एक्सटेंशन के माध्यम से WCF करने के लिए एक थ्रॉटलिंग तंत्र को जोड़ने का तरीका है, लेकिन फिर बताया गया कि मैं सवाल पढ़ने में भूलना चर्चा की (doh!)।

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

Throttling method calls to M requests in N seconds

आप दर सीमा का उल्लंघन कर रहे हैं, तो एक फिक्स अंतराल के लिए सोने और फिर से जाँच। यदि नहीं, तो आगे बढ़ें और HttpWebRequest कॉल करें।

+0

प्रश्न में, मैं एक WCF वेब सेवा की बात नहीं कर रहा हूँ। यह एक साधारण HttpWebRequest वर्ग उपयोग के बारे में है। –

+0

आह देर हो चुकी है और मुझे प्रश्न को और अधिक बारीकी से पढ़ना चाहिए :) आप अभी भी HttpWebRequest पर कॉल करने से पहले दृष्टिकोण का प्रयास कर सकते हैं, यह सुनिश्चित करने के लिए कि आप 80 अनुरोध/सेकंड दर का उल्लंघन नहीं करेंगे, किसी अन्य वर्ग से जांचें। मैं उपरोक्त अपना कोड अपडेट करूंगा। –

+0

यह सी # जावा के लिए नहीं पूछा। – SmallChess

0

थ्रॉटल() और नमूना() विस्तार तरीकों (प्रत्यक्ष पर) यदि आप एक "धीमे" अनुक्रम में घटनाओं की एक तेजी से अनुक्रम विनियमित करने की अनुमति।

Sample(Timespan) कि एक maxium दर सुनिश्चित करता है की Here is a blog post with an example

+0

नमूना() और थ्रोटल() के साथ समस्या यह है कि वे निर्दिष्ट दर प्राप्त करने के लिए नमूनों को छोड़कर फेंक देते हैं। – georgiosd

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