github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/framework/cache/write_delete.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 "errors" 24 "fmt" 25 "time" 26 27 "github.com/mdaxf/iac/framework/berror" 28 ) 29 30 type WriteDeleteCache struct { 31 Cache 32 storeFunc func(ctx context.Context, key string, val any) error 33 } 34 35 // NewWriteDeleteCache creates a write delete cache pattern decorator. 36 // The fn is the function that persistent the key and val. 37 func NewWriteDeleteCache(cache Cache, fn func(ctx context.Context, key string, val any) error) (*WriteDeleteCache, error) { 38 if fn == nil || cache == nil { 39 return nil, berror.Error(InvalidInitParameters, "cache or storeFunc can not be nil") 40 } 41 42 w := &WriteDeleteCache{ 43 Cache: cache, 44 storeFunc: fn, 45 } 46 return w, nil 47 } 48 49 func (w *WriteDeleteCache) Set(ctx context.Context, key string, val any) error { 50 err := w.storeFunc(ctx, key, val) 51 if err != nil && !errors.Is(err, context.DeadlineExceeded) { 52 return berror.Wrap(err, PersistCacheFailed, fmt.Sprintf("key: %s, val: %v", key, val)) 53 } 54 return w.Cache.Delete(ctx, key) 55 } 56 57 // WriteDoubleDeleteCache creates write double delete cache pattern decorator. 58 // The fn is the function that persistent the key and val. 59 // it will delete the key from cache when you call Set function, and wait for interval, it will delete the key from cache one more time. 60 // This pattern help to reduce the possibility of data inconsistencies, but it's still possible to be inconsistent among database and cache. 61 type WriteDoubleDeleteCache struct { 62 Cache 63 interval time.Duration 64 timeout time.Duration 65 storeFunc func(ctx context.Context, key string, val any) error 66 } 67 68 type WriteDoubleDeleteCacheOption func(c *WriteDoubleDeleteCache) 69 70 func NewWriteDoubleDeleteCache(cache Cache, interval, timeout time.Duration, 71 fn func(ctx context.Context, key string, val any) error) (*WriteDoubleDeleteCache, error) { 72 if fn == nil || cache == nil { 73 return nil, berror.Error(InvalidInitParameters, "cache or storeFunc can not be nil") 74 } 75 76 return &WriteDoubleDeleteCache{ 77 Cache: cache, 78 interval: interval, 79 timeout: timeout, 80 storeFunc: fn, 81 }, nil 82 } 83 84 func (c *WriteDoubleDeleteCache) Set( 85 ctx context.Context, key string, val any) error { 86 err := c.storeFunc(ctx, key, val) 87 if err != nil && !errors.Is(err, context.DeadlineExceeded) { 88 return berror.Wrap(err, PersistCacheFailed, fmt.Sprintf("key: %s, val: %v", key, val)) 89 } 90 time.AfterFunc(c.interval, func() { 91 rCtx, cancel := context.WithTimeout(context.Background(), c.timeout) 92 _ = c.Cache.Delete(rCtx, key) 93 cancel() 94 }) 95 err = c.Cache.Delete(ctx, key) 96 if err != nil { 97 return berror.Wrap(err, DeleteFailed, fmt.Sprintf("write double delete pattern failed to delete the key: %s", key)) 98 } 99 return nil 100 }