diff --git a/example55-cache-hotspot-invalid/main.go b/example55-cache-hotspot-invalid/main.go index fe1842c..021e966 100644 --- a/example55-cache-hotspot-invalid/main.go +++ b/example55-cache-hotspot-invalid/main.go @@ -29,13 +29,26 @@ func main() { } wg.Wait() - slog.Info("================== using singleflight ===================") + slog.Info("================== using singleflight Do ===================") wg.Add(5) for i := 5; i < 10; i++ { go func(req int) { defer wg.Done() - data := db.GetArticleNew(req, 2) + data := db.GetArticleDo(req, 2) + slog.Info("data info", "data", data, "req", req) + }(i) + } + wg.Wait() + + slog.Info("================== using singleflight DoChan ===================") + + wg.Add(5) + for i := 10; i < 15; i++ { + go func(req int) { + defer wg.Done() + t := time.Duration(time.Duration(int64(req*10)) * time.Millisecond) + data := db.GetArticleDoChan(req, 3, t) slog.Info("data info", "data", data, "req", req) }(i) } @@ -64,7 +77,7 @@ func (db *DB) GetArticleOld(req int, id int) *Article { return data } -func (db *DB) GetArticleNew(req int, id int) *Article { +func (db *DB) GetArticleDo(req int, id int) *Article { data := db.cache.Get(id) if data != nil { slog.Info("cache hit", "id", id, "req", req) @@ -90,3 +103,31 @@ func (db *DB) GetArticleNew(req int, id int) *Article { return row.(*Article) } + +func (db *DB) GetArticleDoChan(req int, id int, t time.Duration) *Article { + data := db.cache.Get(id) + if data != nil { + slog.Info("cache hit", "id", id, "req", req) + return data + } + + key := fmt.Sprintf("article:%d", id) + dataChan := db.engine.DoChan(key, func() (interface{}, error) { + slog.Info("missing cache", "id", id, "req", req) + data := &Article{ + ID: id, + Content: "FooBar", + } + db.cache.Set(id, data) + time.Sleep(115 * time.Millisecond) + return data, nil + }) + + select { + case <-time.After(t): + slog.Info("timeout", "id", id, "req", req) + return nil + case res := <-dataChan: + return res.Val.(*Article) + } +}