2013-02-19 44 views
10

उपयोगकर्ता द्वारा निर्धारित समय/आवृत्ति सेट के साथ पुनरावर्ती कार्यों को सही ढंग से कार्यान्वित करने के लिए कैसे करें अंतिम वीडियो वाले ईमेल की सदस्यता लें, लेकिन वे यह ईमेल भी कब सेट करते हैं।उपयोगकर्ता

Subscription(user_id, frequency, day, time, time_zone) 

user_id | frequency | day | time | time_zone 
1  | daily  | null | 16:00 | GMT 
2  | weekly  | friday | 11:00 | UTC 
3  | weekly  | monday | 18:00 | EST 

हम कैसे, पंगा लेना

केवल आवृत्तियों दैनिक और साप्ताहिक हैं (डबल ईमेल भेजने या लापता समय की तरह) के बिना अपने समय क्षेत्र में उपयोगकर्ताओं द्वारा चुना सही समय और आवृत्ति पर ईमेल भेज सकते हैं यदि दैनिक तो दिन शून्य है।

मैं इसके लिए डेटाबेस के रूप में रेडिस का उपयोग करता हूं, मुझे बताएं कि यह सही तरीके से कैसे करें!

+0

- https://github.com/collectiveidea/delayed_job - आप कुछ भी करने के लिए हर काम पर run_at सेट कर सकते हैं आप चाहते हैं (अपने सदस्यता समय से मेल खाते हैं, प्रति शेड्यूल एक नौकरी) तो जब नौकरी पूरी हो रही है तो यह आपके शेड्यूलर सेटिंग – house9

+0

के आधार पर फिर से चलाने के लिए खुद को लागू कर लेता है आपको कितना सटीक होना चाहिए? यदि यह एक मिनट तक है, तो क्या यह स्वीकार्य है? –

उत्तर

0

मुझे लगता है कि आप इस उद्देश्य के लिए इस मणि का लाभ उठाने कर सकते हैं: https://github.com/bvandenbos/resque-scheduler

सादर,

+0

सुनिश्चित नहीं हैं कि अगर यह सही समाधान है, लगता है जैसे आप डायनामिक रूप से तैयार (एक YAML विन्यास फाइल का उपयोग नहीं) आवर्ती कार्यों – Ryan

+0

@Ryan कार्य विन्यास राज्यों अन्यथा में नहीं हो सकता है: # आप गतिशील रूप से शेड्यूल परिवर्तित करने में सक्षम होना चाहते हैं , # इस लाइन को असंबद्ध करें। एक गतिशील अनुसूची # Resque :: Scheduler.set_schedule (और remove_schedule) विधियों के माध्यम से अपडेट की जा सकती है। # जब गतिशील सत्य पर सेट किया जाता है, तो शेड्यूलर प्रक्रिया # शेड्यूल परिवर्तनों को देखती है और उन्हें फ्लाई पर लागू करती है। # नोट: यह सुविधा केवल> = 2.0.0 में उपलब्ध है। # रीस्क :: शेड्यूलर.dynamic = true – fmendez

0

आप DelayedJob या Resque रत्न है, जो प्रत्येक के रूप में एक निर्धारित कार्य के कहने प्रतिनिधित्व करते हैं इस्तेमाल कर सकते हैं डेटाबेस तालिका में एक पंक्ति। कैलेंडर से कार्यों को ट्रिगर करने, शेड्यूल करने और निकालने के तरीके हैं।

1

मैंने अतीत में इसी तरह के कार्यों के लिए delayed_job का उपयोग किया है। शायद आप उसी तकनीक का उपयोग resque के साथ कर सकते हैं। अनिवार्य रूप से, आपको वर्तमान नौकरी के अंत में अगली नौकरी निर्धारित करना होगा।

class Subscription < ActiveRecord::Base 
    after_create :send_email   
    def send_email 
    # do stuff and then schedule the next run 
    ensure 
    send_email 
    end 
    handle_asynchronously :send_email, :run_at => Proc.new{|s| s.deliver_at } 

    def daily? (frequency == "daily");end 
    def max_attempts 1;end 

    def time_sec 
    hour,min=time.split(":").map(&:to_i) 
    hour.hours + min.minutes 
    end 

    def days_sec 
    day.nil? ? 0 : Time::DAYS_INTO_WEEK[day.to_sym].days 
    end 

    def interval_start_time 
    time = Time.now.in_time_zone(time_zone) 
    daily? ? time.beginning_of_day : time.beginning_of_week 
    end 

    def deliver_at 
    run_at = interval_start_time + days_sec + time_sec 
    if time.past? 
     run_at = daily? ? run_at.tomorrow : 1.week.from_now(run_at) 
    end 
    run_at 
    end   
end 

पुनर्निर्धारण चेतावनियां

अद्यतन चक्र समाप्ति को संभालने के लिए कोड। आप इसे boolean कॉलम active नामक कॉलम जोड़कर इसे संभाल सकते हैं (इसे डिफ़ॉल्ट रूप से true पर सेट करें)। सदस्यता को अक्षम करने के लिए, कॉलम को गलत पर सेट करें।

def send_email 
    return unless active? 
    # do stuff and then schedule the next run 
    ensure 
    send_email if active? 
    end 

1. करने के लिए नौकरी के लिए max_attempts सेट नहीं तो आप कतार में बाढ़ होगा। उपरोक्त समाधान में, send_email के लिए नौकरियों का एक बार प्रयास किया जाएगा।

+0

ने 'max_attempts' को सुन्दर तरीके से संभालने के लिए उत्तर अपडेट किया। –

2

मैं resque-scheduler gem का उपयोग कर fmendez के उत्तर पर विस्तार करने जा रहा हूं।

पहले, आइए, कार्यकर्ता ईमेल

class SubscriptionWorker 
    def self.perform(subscription_id) 
    subscription = Subscription.find subscription_id 

    # .... 
    # handle sending emails here 
    # .... 

    # Make sure that you don't have duplicate workers 
    Resque.remove_delayed(SubscriptionWorker, subscription_id)   

    # this actually calls this same worker but sets it up to work on the next 
    # sending time of the subscription. next_sending_time is a method that 
    # we implement in the subscription model. 
    Resque.enqueue_at(subscription.next_sending_time, SubscriptionWorker, subscription_id) 
    end 
end 

भेजता है अपनी सदस्यता मॉडल में बनाने अगली बार एक ई-मेल भेजा जाना चाहिए गणना करने के लिए एक next_sending_time विधि जोड़ते हैं।

# subscription.rb 
def next_sending_time 
    parsed_time = Time.parse("#{time} #{time_zone}") + 1.day 

    if frequency == 'daily' 
    parsed_time 
    else 
    # this adds a day until the date matches the day in the subscription 
    while parsed_time.strftime("%A").downcase != day.downcase 
     parsed_time += 1.day 
    end 
    end 
end 
0

मैं सिर्फ अपनी परियोजना के लिए इस क्रियान्वित किया है, मैं इसे जब भी रत्न (यहाँ https://github.com/javan/whenever मौजूद) का उपयोग करने के लिए है करने के लिए एक बहुत आसान तरीका मिल गया है।

आरंभ करने के लिए, अपने ऐप के पास जाकर

gem 'whenever' 

डाल तो का उपयोग करें:

wheneverize . 

टर्मिनल में।यह आपके कॉन्फ़िगरेशन फ़ोल्डर में शेड्यूल.आरबी फाइल बनाएगा।

आप अपने नियम अपने शेड्यूल.आरबी (नीचे दिखाए गए) में डालते हैं और उन्हें कुछ तरीकों को कॉल करने देते हैं - उदाहरण के लिए, मेरा मॉडल विधि DataProviderUser.cron को कॉल करता है जो मेरे पास जो भी कोड चलाएगा।

एक बार जब आप इस फाइल को बना लिया है, क्रॉन जॉब शुरू करने के लिए, कमांड लाइन प्रयोग पर:

whenever 
whenever -w 

और

whenever -c 

बंद हो जाता है/क्रॉन नौकरियों साफ करता है।

GitHub पर जवाहरात प्रलेखन वास्तव में उपयोगी है, लेकिन मैं सुझाव है कि आप अपने खुद के लॉग फ़ाइल के लिए उत्पादन सेट (के रूप में मैं नीचे किया है)। आशा है कि मदद करता है :)

मेरी schedule.rb में मेरे पास है:

set :output, 'log/cron.log' 
every :hour do 
runner "DataProviderUser.cron('hourly')" 
end 

every :day do 
runner "DataProviderUser.cron('daily')" 
end 

every '0 0 * * 0' do 
runner "DataProviderUser.cron('weekly')" 
end 

every 14.days do 
runner "DataProviderUser.cron('fortnightly')" 
end 

every :month do 
runner "DataProviderUser.cron('monthly')" 
end 
1

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

सबसे पहले, अपने सभी समय आंतरिक रूप से जीएमटी के रूप में स्टोर करें। टाइमज़ोन वास्तविक नहीं हैं, वरीयता सेटिंग (उपयोगकर्ता की तालिका में) होने के अलावा, जो दृश्य में समय को ऑफ़सेट करता है। समन्वय प्रणाली जिसमें गणित किया जाता है, लगातार होना चाहिए।

फिर प्रत्येक आवृत्ति एक क्रोनबॉज सेटिंग से मेल खाती है: दैनिक, सोमवार, मंगलवार, आदि। वास्तव में, तालिका में डेटा से, आपको दो स्तंभों की आवश्यकता नहीं है, जब तक कि आप इसे बदलने के रूप में नहीं देखते।

फिर

, जब क्रॉन आग, जब ईमेल बाहर चला जाता है संभाल करने के लिए एक अनुसूचक (linux AT की तरह) का उपयोग करें। यह सिस्टम स्तर शेड्यूलिंग समस्या से अधिक है, या कम से कम, मैं इसे संभालने के लिए सिस्टम पर अधिक भरोसा करता हूं। सेवाओं और ऐप सहित सिस्टम को फिर से शुरू करने के मामले में इसे संभालने की आवश्यकता है।

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

तो मूल रूप से:

क्रॉन -> पर -> यदि आप delayed_job उपयोग कर रहे थे मेल भेजने