Class: Faraday::ObjectCache

Inherits:
Middleware
  • Object
show all
Defined in:
lib/ontologies_api_client/middleware/faraday-object-cache.rb

Overview

This middleware causes Faraday to return an actual object instead of a response This is done so that the object is cached instead of the unparsed json body. Otherwise, we have to re-parse the json on every cache hit, which is extrememly costly when compared to unmarshaling an object.

Defined Under Namespace

Classes: CompressedMemcache

Instance Method Summary collapse

Constructor Details

#initialize(app, *arguments) ⇒ ObjectCache

Returns a new instance of ObjectCache.



17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/ontologies_api_client/middleware/faraday-object-cache.rb', line 17

def initialize(app, *arguments)
  super(app)

  if arguments.last.is_a? Hash
    options = arguments.pop
    @logger = options.delete(:logger)
  else
    options = arguments
  end

  @store = options[:store] || ActiveSupport::Cache.lookup_store(store, options)
end

Instance Method Details

#call(env) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/ontologies_api_client/middleware/faraday-object-cache.rb', line 30

def call(env)
  invalidate_cache = env[:request_headers].delete(:invalidate_cache)

  # Add if newer than last modified statement to headers
  request_key = cache_key_for(create_request(env))
  last_modified_key = "LM::#{request_key}"
  last_retrieved_key = "LR::#{request_key}"

  # If we invalidate the cache, then it forces a clean request
  if invalidate_cache
    cache_delete(request_key)
    cache_delete(last_modified_key)
    cache_delete(last_retrieved_key)
    env[:request_headers]["Cache-Control"] = "no-cache"
  end

  # If we made the last request within the expiry
  if cache_exist?(last_retrieved_key) && cache_exist?(request_key)
    puts "DEBUG not expired #{env[:url].to_s}" if $CACHE_DEBUG
    cached_item = cache_read(request_key)
    ld_obj = cached_item.is_a?(Hash) && cached_item.key?(:ld_obj) ? cached_item[:ld_obj] : cached_item
    env[:status] = 304
    cached_response = ObjectCacheResponse.new(env)
    cached_response.parsed_body = ld_obj
    return cached_response
  end

  last_modified = cache_read(last_modified_key)
  headers = env[:request_headers]
  puts "DEBUG last modified: " + last_modified.to_s if last_modified && $CACHE_DEBUG
  headers['If-Modified-Since'] = last_modified if last_modified

  @app.call(env).on_complete do |response_env|
    # Only cache get and head requests
    if [:get, :head].include?(response_env[:method])
      puts "DEBUG response status: " + response_env[:status].to_s if $CACHE_DEBUG

      last_modified = response_env[:response_headers]["Last-Modified"]

      # Generate key using header hash
      key = request_key

      # If the last retrieve time is less than expiry
      if response_env[:status] == 304 && cache_exist?(key)
        stored_obj = cache_read(key)

        # Update if last modified is different
        if stored_obj[:last_modified] != last_modified
          puts "UPDATING CACHE #{response_env[:url].to_s}" if $CACHE_DEBUG
          stored_obj[:last_modified] = last_modified
          cache_write(last_modified_key, last_modified)
          cache_write(key, stored_obj)
        end

        ld_obj = stored_obj[:ld_obj]
      else
        if response_env[:body].nil? || response_env[:body].empty?
          # We got here with an empty body, meaning the object wasn't
          # in the cache (weird). So re-do the request.
          puts "REDOING REQUEST NO CACHE ENTRY #{response_env[:url].to_s}"
          env[:request_headers].delete("If-Modified-Since")
          response_env = @app.call(env).env
        end
        ld_obj = LinkedData::Client::HTTP.object_from_json(response_env[:body])
        expiry = response_env[:response_headers]["Cache-Control"].to_s.split("max-age=").last.to_i
        if expiry > 0 && last_modified
          # This request is cacheable, store it
          puts "STORING OBJECT: #{response_env[:url].to_s}" if $CACHE_DEBUG
          stored_obj = {last_modified: last_modified, ld_obj: ld_obj}
          cache_write(last_modified_key, last_modified)
          cache_write(last_retrieved_key, true, expires_in: expiry)
          cache_write(key, stored_obj)
        end
      end

      response = ObjectCacheResponse.new(response_env)
      response.parsed_body = ld_obj
      return response
    end
  end
end