Sha256: 048ba6bd48a4e2903d8e6a88dbfa6de38f3dce3a02882df3549c5e85820196fb

Contents?: true

Size: 1.98 KB

Versions: 1

Compression:

Stored size: 1.98 KB

Contents

require 'bigdecimal'
require 'money/distributed/redis'

class Money
  module Distributed
    # Storage for `Money::Bank::VariableExchange` that stores rates in Redis
    class Storage
      INDEX_KEY_SEPARATOR = '_TO_'.freeze
      REDIS_KEY = 'money_rates'.freeze

      def initialize(redis, cache_ttl = nil)
        @redis = Money::Distributed::Redis.new(redis)

        @cache = {}
        @cache_ttl = cache_ttl
        @cache_updated_at = nil

        @mutex = Mutex.new
      end

      def add_rate(iso_from, iso_to, rate)
        @redis.exec do |r|
          r.hset(REDIS_KEY, key_for(iso_from, iso_to), rate)
        end
        clear_cache
      end

      def get_rate(iso_from, iso_to)
        cached_rates[key_for(iso_from, iso_to)]
      end

      def each_rate
        enum = Enumerator.new do |yielder|
          cached_rates.each do |key, rate|
            iso_from, iso_to = key.split(INDEX_KEY_SEPARATOR)
            yielder.yield iso_from, iso_to, rate
          end
        end

        block_given? ? enum.each(&block) : enum
      end

      def transaction
        # We don't need transactions, we all thread safe here
        yield
      end

      def marshal_dump
        [self.class, @cache_ttl]
      end

      private

      def key_for(iso_from, iso_to)
        [iso_from, iso_to].join(INDEX_KEY_SEPARATOR).upcase
      end

      def cached_rates
        @mutex.synchronize do
          retrieve_rates if @cache.empty? || cache_outdated?
          @cache
        end
      end

      def cache_outdated?
        return false unless @cache_ttl
        @cache_updated_at.nil? ||
          @cache_updated_at < Time.now - @cache_ttl
      end

      def clear_cache
        @mutex.synchronize do
          @cache.clear
        end
      end

      def retrieve_rates
        @redis.exec do |r|
          r.hgetall(REDIS_KEY).each_with_object(@cache) do |(key, val), h|
            h[key] = BigDecimal.new(val)
          end
        end
        @cache_updated_at = Time.now
      end
    end
  end
end

Version data entries

1 entries across 1 versions & 1 rubygems

Version Path
money-distributed-0.0.2.2 lib/money/distributed/storage.rb