1時に寝て7時に起きた。リリース延期を決めたので3月末へのストレスやプレッシャーからは解放されていつもよりよく眠れた気がした。あくまで気がしただけ。

キャッシュライブラリの選定

ある機能を作るための準備としてキャッシュ機構を作ることにした。avelino/awesome-go を眺めて適当なキャッシュライブラリを選定する。シンプルな用途向け、オンメモリで goroutine-safe で保守されていて実績があるものでのバランスを取るときむらさんのキャッシュライブラリになった。

ちょうどいまのお仕事を始める前に スカウトをもらった会社 のテックリードがきむらさんだったので、いまはその会社にいるんだと思い出したのが半年前。きむらさんとはリアルで何年も会っていないし、仲がよいわけでもないけれど、なぜか facebook でも繋がっているので存在を忘れるということもない。

閑話休題。ある特定の mongodb コレクションのデータをキャッシュしたい。

キャッシュの生成。

cache := gcache.New(128).Build()

特定の用途で一部の処理だけ使いたいのでこんな感じでキャッシュの処理を実装した。

value, err := cache.Get(id)
if err == nil {
    return value.(*myData), nil
} else if err != gcache.KeyNotFoundError {
    log.Error("failed to get value from cache", map[string]any{
        "key": id,
        "err": err,
    })
}

// 通常処理

cache.Set(id, setting)

念のため、キャッシュをすべてクリアするときは次を呼ぶ。これをキャッシュ制御 api から呼び出せるようにしておく。何らかの理由やバグなどでキャッシュをクリアする必要もあるだろう。

cache.Purge()

データを削除したときは id 指定でキャッシュを削除する。

cache.Remove(id)

キャッシュが使われているかどうかは内部的に統計を取っているのでそれをキャッシュ制御 api から取得することでわかる。 キャッシュが使われていれば HitCount が増え、mongodb にアクセスしていれば MissCount が増える。単体レベルでプログラムのデバッグにはなる。

return CacheStat{
    HitCount:    cache.HitCount(),
    MissCount:   cache.MissCount(),
    LookupCount: cache.LookupCount(),
    HitRate:     cache.HitRate(),
}