我正在编写一个 API 客户端(库),它命中一个 JSON 端点并填充一个内存缓存。
到目前为止:
- 我在库的 init() 函数中启动了一个 time.Ticker 循环,它每分钟都会访问 API,从而刷新缓存(一个嵌入 JSON 结构和时间戳的结构)。
- 库中面向公众的函数调用只是从 catch 中获取,因此不需要担心自己的速率限制,但如果他们想确认数据的新鲜度,可以检查时间戳<
但是,在 init() 中启动 time.Ticker 感觉不太对:我还没有看到任何其他库这样做。然而,我确实希望避免包用户不得不做大量的工作只是为了从几个 JSON 端点取回数据。
我的公共(public) API 如下所示:
// Example usage:
// rt := api.NewRT()
// err := rt.GetLatest
// tmpl.ExecuteTemplate(w, "my_page.tmpl", M{"results": rt.Data})
func (rt *RealTime) GetLatest() error {
rt = realtimeCache.Cached
if rt == nil {
return errors.New("No cached response is available.")
}
return nil
}
内部 getter 如下:
func fetchLatest() error {
log.Println("Fetching latest RT results.")
resp, err := http.Get(realtimeEndpoint)
if err != nil {
return err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
// Lock our cache from writes
realtimeCache.Lock()
defer realtimeCache.Unlock()
var rt *RealTime
err = json.Unmarshal(body, &rt)
if err != nil {
return err
}
// Update the cache
realtimeCache.Cached = rt
return nil
}
func init() {
// Populate the cache on start-up
fetchLatest()
fetchHistorical()
// Refresh the cache every minute (default)
ticker := time.NewTicker(time.Second * interval)
go func() {
for _ = range ticker.C {
fetchLatest()
fetchHistorical()
}
}()
}
API 的其他部分也有类似的功能(我正在模块化,但我一开始就保持简单),但这就是它的要点。
有没有更好的方法让后台 worker 获取仍然对用户友好的结果?
最佳答案
恕我直言,在 init()
函数上启动计时器是个坏主意,原因很简单,您的 API 的用户应该决定是否以及何时进行抓取/缓存/更新。
我建议使用 NewRT()
函数中的选项或包范围的 bool 值(api.AutoUpdate
, api.Caching
).
根据访问者的要求,您可以采取适当的行动:
- 如果未启用缓存,则检索数据
- 如果启用了缓存但未启用自动更新,则检查数据的新鲜度,并在需要时刷新
- 如果启用了缓存和自动更新,则什么都不做,因为您的计时器(在
NewRT()
函数中启动)将为您处理数据
这样您就不会在用户需要之前开始检索任何内容,而是可以灵活地让您的用户决定他们是否需要额外的功能。
请注意,您应该确保在删除相应的结构后不会保留不必要的计时器。
关于json - API 库中的后台获取,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24375671/