2017-05-08 50 views
4

在我的Rails應用程序我想在緩存從外部服務獲取了一些貨幣的匯率,並將其儲存:如何處理Open-Uri中的外部服務故障?

require 'open-uri' 

module ExchangeRate 

    def self.all 
    Rails.cache.fetch("exchange_rates", :expires_in => 24.hours) { load_all } 
    end 

    private 

    def self.load_all 
     hashes = {} 
     CURRENCIES.each do |currency| 
     begin 
      hash = JSON.parse(open(URI("http://api.fixer.io/latest?base=#{currency}")).read) #what if not available? 
      hashes[currency] = hash["rates"] 
     rescue Timeout::Error 
      puts "Timeout" 
     rescue OpenURI::Error => e 
      puts e.message 
     end 
     end 
     hashes 
    end 

end 

這個工作在發展不錯,但我擔心的是生產環境。如果外部服務不可用,我怎樣才能防止整個事物被緩存?我如何確保ExchangeRate.all始終包含數據,即使它已經過時並且由於外部服務失敗而無法更新?

我試圖添加一些基本的錯誤處理,但恐怕還不夠。

+1

你可能例如保持「exchange_rates_backup」,將不會過期的另一個緩存,這將是每一個外部服務將被成功讀取時間設置。然後這個「備份」緩存可以在'all'方法中用作備份。 – BoraMa

+0

您可以依賴數據庫中的自定義表。如果'load_all'失敗,則可以使用自己表中的記錄。 – etagwerker

回答

0

如果您擔心外部服務不夠可靠,無法跟上每24小時的緩存速度,那麼您應該禁用自動緩存過期,讓用戶使用舊數據並設置某種通知系統告訴你load_all是否失敗。

這是我會怎麼做:

  1. 假設ExchangeRate.all總是返回緩存副本,沒有到期(這將返回nil如果沒有高速緩存中找到):

    module ExchangeRate 
        def self.all 
        rates = Rails.cache.fetch("exchange_rates") 
        UpdateCurrenciesJob.perform_later if rates.nil? 
        rates 
        end 
    end 
    
  2. 創建定期處理更新的ActiveJob:

    class UpdateCurrenciesJob < ApplicationJob 
        queue_as :default 
    
        def perform(*_args) 
        hashes = {} 
        CURRENCIES.each do |currency| 
         begin 
         hash = JSON.parse(open(URI("http://api.fixer.io/latest?base=#{currency}")).read) # what if not available? 
         hashes[currency] = hash['rates'].merge('updated_at' => Time.current) 
         rescue Timeout::Error 
         puts 'Timeout' 
         rescue OpenURI::Error => e 
         puts e.message 
         end 
    
         if hashes[currency].blank? || hashes[currency]['updated_at'] < Time.current - 24.hours 
         # send a mail saying "this currency hasn't been updated" 
         end 
        end 
    
        Rails.cache.write('exchange_rates', hashes) 
        end 
    end 
    
  3. 將作業設置爲每隔幾小時運行一次(4,8,12,小於24)。這樣,貨幣將在後臺加載,客戶將始終擁有數據,並且您將始終知道貨幣是否無效。