Class: Factorix::HTTP::CacheDecorator

Inherits:
Object
  • Object
show all
Defined in:
lib/factorix/http/cache_decorator.rb,
sig/factorix/http/cache_decorator.rbs

Overview

Adds caching for GET requests

Stores successful GET responses in FileSystem cache. Only caches non-streaming requests (no block given).

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#cache ⇒ Cache::FileSystem (readonly)

Returns the value of attribute cache.

Returns:



13
14
15
# File 'sig/factorix/http/cache_decorator.rbs', line 13

def cache
  @cache
end

#client ⇒ Client (readonly)

Returns the value of attribute client.

Returns:



12
13
14
# File 'sig/factorix/http/cache_decorator.rbs', line 12

def client
  @client
end

#logger ⇒ Dry::Logger::Dispatcher (readonly)

Returns the value of attribute logger.



14
15
16
# File 'sig/factorix/http/cache_decorator.rbs', line 14

def logger
  @logger
end

Instance Method Details

#get(uri, headers: {}) {|Net::HTTPResponse| ... } ⇒ Response, Object

Execute a GET request with caching

Parameters:

  • uri (URI::HTTPS) —

    target URI

  • headers (Hash<String, String>) (defaults to: {}) —

    request headers

  • headers: (Hash[String, String]) (defaults to: {})

Yields:

  • (Net::HTTPResponse) —

    for streaming responses

Returns:

  • (Response, Object) —

    response object or parsed data



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
# File 'lib/factorix/http/cache_decorator.rb', line 49

def get(uri, headers: {}, &block)
  # Don't cache streaming requests
  return client.get(uri, headers:, &block) if block

  cache_key = uri.to_s

  cached_body = cache.read(cache_key)
  if cached_body
    logger.debug("Cache hit", uri: uri.to_s)
    publish("cache.hit", url: uri.to_s)
    return CachedResponse.new(cached_body, uri:)
  end

  logger.debug("Cache miss", uri: uri.to_s)
  publish("cache.miss", url: uri.to_s)

  # Locking prevents concurrent downloads of the same resource
  cache.with_lock(cache_key) do
    # Double-check: another thread might have filled the cache
    cached_body = cache.read(cache_key)
    if cached_body
      publish("cache.hit", url: uri.to_s)
      return CachedResponse.new(cached_body, uri:)
    end

    response = client.get(uri, headers:)

    if response.success?
      with_temporary_file do |temp|
        temp.write(response.body)
        temp.close
        cache.store(cache_key, Pathname(temp.path))
      end
    end

    response
  end
end

#head(uri, headers: {}) ⇒ Response

Execute a HEAD request (never cached)

Parameters:

  • uri (URI::HTTPS) —

    target URI

  • headers (Hash<String, String>) (defaults to: {}) —

    request headers

Returns:



102
# File 'lib/factorix/http/cache_decorator.rb', line 102

def head(uri, headers: {}) = client.head(uri, headers:)

#post(uri, body:, headers: {}, content_type: nil) ⇒ Response

Execute a POST request (never cached)

Parameters:

  • uri (URI::HTTPS) —

    target URI

  • body (String, IO) —

    request body

  • headers (Hash<String, String>) (defaults to: {}) —

    request headers

  • content_type (String, nil) (defaults to: nil) —

    Content-Type header

  • body: (String, IO)
  • headers: (Hash[String, String]) (defaults to: {})
  • content_type: (String, nil) (defaults to: nil)

Returns:



95
# File 'lib/factorix/http/cache_decorator.rb', line 95

def post(uri, body:, headers: {}, content_type: nil) = client.post(uri, body:, headers:, content_type:)

#request(method, uri, headers: {}, body: nil) {|Net::HTTPResponse| ... } ⇒ Response, Object

Execute an HTTP request (only caches GET without block)

Parameters:

  • method (Symbol) —

    HTTP method

  • uri (URI::HTTPS) —

    target URI

  • headers (Hash<String, String>) (defaults to: {}) —

    request headers

  • body (String, IO, nil) (defaults to: nil) —

    request body

  • headers: (Hash[String, String]) (defaults to: {})
  • body: (String, IO, nil) (defaults to: nil)

Yields:

  • (Net::HTTPResponse) —

    for streaming responses

Returns:

  • (Response, Object) —

    response object or parsed data



35
36
37
38
39
40
41
# File 'lib/factorix/http/cache_decorator.rb', line 35

def request(method, uri, headers: {}, body: nil, &block)
  if method == :get && !block
    get(uri, headers:)
  else
    client.request(method, uri, headers:, body:, &block)
  end
end