2017-05-08 49 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)。这样,货币将在后台加载,客户将始终拥有数据,并且您将始终知道货币是否无效。