github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/framework/cache/singleflight.go (about) 1 // The package is migrated from beego, you can get from following link: 2 // import( 3 // "github.com/beego/beego/v2/client/cache" 4 // ) 5 // Copyright 2023. All Rights Reserved. 6 // 7 // Licensed under the Apache License, Version 2.0 (the "License"); 8 // you may not use this file except in compliance with the License. 9 // You may obtain a copy of the License at 10 // 11 // http://www.apache.org/licenses/LICENSE-2.0 12 // 13 // Unless required by applicable law or agreed to in writing, software 14 // distributed under the License is distributed on an "AS IS" BASIS, 15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 // See the License for the specific language governing permissions and 17 // limitations under the License. 18 19 package cache 20 21 import ( 22 "context" 23 "time" 24 25 "golang.org/x/sync/singleflight" 26 27 "github.com/mdaxf/iac/framework/berror" 28 ) 29 30 // SingleflightCache 31 // This is a very simple decorator mode 32 type SingleflightCache struct { 33 Cache 34 group *singleflight.Group 35 expiration time.Duration 36 loadFunc func(ctx context.Context, key string) (any, error) 37 } 38 39 // NewSingleflightCache create SingleflightCache 40 func NewSingleflightCache(c Cache, expiration time.Duration, 41 loadFunc func(ctx context.Context, key string) (any, error), 42 ) (Cache, error) { 43 if loadFunc == nil { 44 return nil, berror.Error(InvalidLoadFunc, "loadFunc cannot be nil") 45 } 46 return &SingleflightCache{ 47 Cache: c, 48 group: &singleflight.Group{}, 49 expiration: expiration, 50 loadFunc: loadFunc, 51 }, nil 52 } 53 54 // Get In the Get method, single flight is used to load data and write back the cache. 55 func (s *SingleflightCache) Get(ctx context.Context, key string) (any, error) { 56 val, err := s.Cache.Get(ctx, key) 57 if val == nil || err != nil { 58 val, err, _ = s.group.Do(key, func() (interface{}, error) { 59 v, er := s.loadFunc(ctx, key) 60 if er != nil { 61 return nil, berror.Wrap(er, LoadFuncFailed, "cache unable to load data") 62 } 63 er = s.Cache.Put(ctx, key, v, s.expiration) 64 return v, er 65 }) 66 } 67 return val, err 68 }