2

我的应用程序做了很多页面抓取,例如获取历史天气数据。获取特定页面后,我想将其缓存在我的 PostgreSQL 数据库中,这样我就不必为该特定请求再次访问远程服务器。

由于历史数据永远不会改变,我想“永远”缓存它们——这需要将缓存的页面存储在长期持久存储中,例如数据库。

我编写了一个基本的缓存机制,它围绕着 Mechanize。它有效,但似乎有比我更好的编码能力的人已经实现了这个。

是否有任何宝石或图书馆已经这样做了?

4

4 回答 4

1

所以我想了又想,看了 Mechanize 和 VCR 的源代码,我决定我真的只是在想这个问题。以下内容可以满足我的需要。(我正在使用 DataMapper,但将其转换为 ActiveRecord 模型会很简单):

class WebCache
  include DataMapper::Resource

  property :id, Serial
  property :serialized_key, Text
  property :serialized_value, Text
  property :created_at, DateTime
  property :updated_at, DateTime

  def with_db_cache(akey)
    serialized_key = YAML.dump(akey)
    if (r = self.all(:serialized_key => serialized_key)).count != 0
      # cache hit: return the de-serialized value
      YAML.load(r.first.serialized_value)
    else
      # cache miss: evaluate the block, serialize and cache the result
      yield(akey).tap {|avalue| 
        self.create(:serialized_key => serialized_key, 
                    :serialized_value => YAML.dump(avalue))
      }
    end
  end
end

示例用法:

def fetch(uri)
  WebCache.with_db_cache(uri) {|uri| 
    # arrive here only on cache miss
    Net::HTTP.get_response(URI(uri))
  }
end

评论

我以前认为,一个适当的网络缓存方案会观察和尊重像 Cache-Control、If-Modified-Since 等头字段,以及自动处理超时和其他网络问题。但是对实际网页的检查清楚地表明,真正的静态数据经常被标记为缓存时间短。因此,让调用者决定缓存多长时间以及何时重试失败的查询更有意义。

那时,代码变得非常简单。

道德:不要过度思考你的问题。

于 2013-02-13T06:13:01.790 回答
0

VCR可能是您想要的。

于 2013-02-10T20:35:25.800 回答
0

也许您应该只使用代理缓存,例如squid。它会比尝试自己做更快、更容易、更可靠。

于 2013-02-10T21:19:17.640 回答
0

您可以查看Open-URI-CacheFaraday-HTTP-Cache。第一个可能更接近您的需要。既不记录到数据库,但也许您可以编写自己的存储层。我没有使用 Heroku 的经验,但文件系统似乎适合这种缓存。

于 2014-09-25T12:30:53.473 回答