2012-04-07 15 views
5

निष्पादित की जाती हैं, मेरा एप्लिकेशन रीस्क जॉब्स बनाता है जिसे प्रति उपयोगकर्ता अनुक्रमिक रूप से संसाधित किया जाना चाहिए, और उन्हें यथासंभव तेज़ी से संसाधित किया जाना चाहिए (1 सेकंड अधिकतम देरी)।रेस्क्यू: समय-महत्वपूर्ण नौकरियां जो अनुक्रमिक रूप से प्रति उपयोगकर्ता

एक उदाहरण: job1 और job2 उपयोगकर्ता 2 के लिए user1 und job3 के लिए बनाया गया है। Resque समानांतर में job1 और job3 को संसाधित कर सकता है, लेकिन job1 और job2 क्रमशः संसाधित किया जाना चाहिए।

मैं एक समाधान के लिए अलग अलग विचार किया है:

  • मैं अलग कतारों इस्तेमाल कर सकते हैं (उदाहरण के लिए queue_1 ... queue_10) और प्रत्येक पंक्ति (जैसे rake resque:work QUEUE=queue_1) के लिए एक कार्यकर्ता शुरू करते हैं। उपयोगकर्ताओं को रनटाइम पर एक कतार/कार्यकर्ता (उदाहरण के लिए लॉगिन, हर दिन इत्यादि) को सौंपा गया है।
  • मैं गतिशील "उपयोगकर्ता कतार" (जैसे कतार _ # {user.id}) का उपयोग कर सकता हूं और resque को विस्तारित करने का प्रयास करता हूं कि केवल 1 कार्यकर्ता एक समय में एक कतार को संसाधित कर सकते हैं (जैसा कि Resque: one worker per queue में पूछा गया है)
  • मैं नौकरियों को एक गैर-रेज्यू कतार में डाल सकता हूं और उन नौकरियों को नियंत्रित करने वाले रेस्क-लॉक (https://github.com/defunkt/resque-lock) के साथ "प्रति-उपयोगकर्ता मेटा जॉब" का उपयोग कर सकता हूं।

क्या आपके पास अभ्यास में से किसी एक परिदृश्य के साथ कोई अनुभव है? या अन्य कोई विचार है जो सोचने लायक हो सकता है? मैं किसी भी इनपुट की सराहना करता हूं, धन्यवाद!

उत्तर

5

@Isotope का जवाब मैं अंत में एक समाधान काम करने के लिए लगता है कि के लिए आया था के लिए धन्यवाद (redis में resque पुन: प्रयास और ताले का उपयोग कर:

class MyJob 
    extend Resque::Plugins::Retry 

    # directly enqueue job when lock occurred 
    @retry_delay = 0 
    # we don't need the limit because sometimes the lock should be cleared 
    @retry_limit = 10000 
    # just catch lock timeouts 
    @retry_exceptions = [Redis::Lock::LockTimeout] 

    def self.perform(user_id, ...) 
    # Lock the job for given user. 
    # If there is already another job for the user in progress, 
    # Redis::Lock::LockTimeout is raised and the job is requeued. 
    Redis::Lock.new("my_job.user##{user_id}", 
     :expiration => 1, 
     # We don't want to wait for the lock, just requeue the job as fast as possible 
     :timeout => 0.1 
    ).lock do 
     # do your stuff here ... 
    end 
    end 
end 

मैं से यहाँ Redis :: ताला उपयोग कर रहा हूँ https://github.com/nateware/redis-objects (यह http://redis.io/commands/setex से पैटर्न समाहित)।

समस्या
2

मैंने पहले यह किया है।

इस तरह की चीजों के लिए अनुक्रमिक रूप से सुनिश्चित करने के लिए सबसे अच्छा समाधान है जॉब 1 कतार नौकरी 2 का अंत होना है। जॉब 1 और जॉब 2 या तो एक ही कतार या अलग कतार में जा सकते हैं, यह अनुक्रमिक रूप से कोई फर्क नहीं पड़ता, यह आपके ऊपर है।

कोई अन्य समाधान, जैसे कि क्यूईइंग जॉब्स 1 + 2 एक ही समय में, लेकिन 0.5secs में शुरू करने के लिए जॉब 2 को बताते हुए दौड़ की स्थिति में परिणाम होगा, इसलिए इसकी अनुशंसा नहीं की जाती है।

नौकरी 1 ट्रिगर जॉब 2 रखना भी वास्तव में आसान है।

यदि आप इसके लिए एक और विकल्प चाहते हैं: मेरा अंतिम सुझाव दोनों नौकरियों को एक ही नौकरी में बंडल करना होगा और दूसरा भाग भी ट्रिगर किया जाना चाहिए।

उदा

def my_job(id, etc, etc, do_job_two = false) 
    ...job_1 stuff... 
    if do_job_two 
    ...job_2 stuff... 
    end 
end 
+0

कि job1 स्पष्ट रूप से, क्योंकि वे वे एक ही समय में नहीं बनाई गई हैं job2 के बारे में पता नहीं करना चाहिए (वे विभिन्न अनुरोधों आदि में बनाया सकता है)। – lacco

+0

जो मामले में है मैं res2-retry का उपयोग, job2 पर, यदि जॉब 1 समाप्त हो गया है और बाद में फिर से कतार नहीं है तो चेक करने के लिए - रेज्यू-रीट्री को आवश्यकतानुसार घातीय बैकऑफ या सीमित ट्रे का उपयोग करने के लिए सेट किया जा सकता है। – TomDunning

+0

जॉब 2 कैसे जानता है कि एक विशिष्ट उपयोगकर्ता के लिए जॉब 1 प्रगति पर है? – lacco

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