如何处理 Open-URI 中的外部服务故障



在我的Rails应用程序中,我试图从外部服务获取多种货币汇率并将它们存储在缓存中:

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始终包含数据,即使数据较旧且由于外部服务故障而无法更新?

我试图添加一些基本的错误处理,但恐怕这还不够。

如果您担心外部服务不够可靠,无法跟上每 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. 创建定期处理更新的活动作业:

    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(。这样,货币将在后台加载,客户端将始终拥有数据,并且您将始终知道货币是否不起作用。

相关内容

  • 没有找到相关文章

最新更新