我的应用会进行大量的页面抓取,例如获取历史天气数据。一旦我获取了一个特定的页面,我想将它缓存在我的PostgreSQL数据库中,这样我就不必为了那个特定的请求而再次点击远程服务器。
由于历史数据永远不会改变,我想“永远”地缓存它们 - 这需要将缓存的页面存储在长期持久存储中,例如一个数据库。
我编写了一个包含Mechanize的基本缓存机制。它有效,但似乎有一个比我更好的编码排序的人已经实现了这个。
是否有任何宝石或图书馆已经这样做了?
答案 0 :(得分: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等,以及自动处理超时和其他网络病理。但是对实际网页的检查清楚地表明,真正的静态数据经常被标记为缓存时间短。因此,让调用者决定缓存某些内容以及何时应该重试失败的查询更有意义。
此时,代码变得非常简单。
道德:不要过度思考你的问题。
答案 1 :(得分:0)
VCR可能就是你想要的。
答案 2 :(得分:0)
也许您应该使用代理缓存,例如squid。它比自己尝试更快,更容易,更可靠。
答案 3 :(得分:0)
您可以查看Open-URI-Cache或Faraday-HTTP-Cache。第一个可能更接近你需要的东西。既不记录到数据库,也可能编写自己的存储层。我没有使用Heroku的经验,但文件系统似乎是这种缓存的正确位置。