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