@@ -13,21 +13,46 @@ import (
13
13
14
14
// CacheClientS3 is a small cache that is backed by an S3-compatible store
15
15
type CacheClientS3 struct {
16
- MC * minio.Client
17
- Bucket string
18
- CTX context.Context
16
+ mc * minio.Client
17
+ bucket string
18
+ ctx context.Context
19
+ defaultExpiration time.Duration
19
20
}
20
21
21
- func (c * CacheClientS3 ) Set (key string , value interface {}, exp time.Duration ) error {
22
- data , err := json .Marshal (value )
23
- if err != nil {
22
+ // NewCacheClientS3 creates a new S3 cache client with default settings
23
+ func NewCacheClientS3 (ctx context.Context , mc * minio.Client , bucket string ) * CacheClientS3 {
24
+ return & CacheClientS3 {
25
+ mc : mc ,
26
+ bucket : bucket ,
27
+ ctx : ctx ,
28
+ defaultExpiration : 24 * time .Hour ,
29
+ }
30
+ }
31
+
32
+ func (c * CacheClientS3 ) Set (key string , value any , exp time.Duration ) error {
33
+ var data bytes.Buffer
34
+ if err := json .NewEncoder (& data ).Encode (value ); err != nil {
24
35
return err
25
36
}
26
37
27
- r := bytes .NewReader (data )
38
+ r := bytes .NewReader (data .Bytes ())
39
+
40
+ // Use the provided expiration time or fall back to default
41
+ expiration := exp
42
+ if expiration == 0 {
43
+ expiration = c .defaultExpiration
44
+ }
45
+
46
+ // Calculate the expiration time
47
+ expiresAt := time .Now ().Add (expiration )
28
48
29
- _ , err = c .MC .PutObject (c .CTX , c .Bucket , key , r , int64 (r .Len ()), minio.PutObjectOptions {
30
- Expires : time .Now ().Add (exp ),
49
+ // Set metadata to track expiration
50
+ metadata := map [string ]string {
51
+ "expires-at" : expiresAt .Format (time .RFC3339 ),
52
+ }
53
+
54
+ _ , err := c .mc .PutObject (c .ctx , c .bucket , key , r , int64 (r .Len ()), minio.PutObjectOptions {
55
+ UserMetadata : metadata ,
31
56
})
32
57
return err
33
58
}
@@ -36,17 +61,27 @@ func (c *CacheClientS3) Set(key string, value interface{}, exp time.Duration) er
36
61
// does not exist, in other case we can use minio.ToErrorResponse(err) to extract more details about the
37
62
// potential S3 related error
38
63
func (c * CacheClientS3 ) Get (key string ) (string , error ) {
39
- if _ , err := c .MC .StatObject (c .CTX , c .Bucket , key , minio.StatObjectOptions {}); err != nil {
64
+ // First check if object exists and get its metadata
65
+ objInfo , err := c .mc .StatObject (c .ctx , c .bucket , key , minio.StatObjectOptions {})
66
+ if err != nil {
40
67
return "" , redis .Nil
41
68
}
42
69
43
- object , err := c .MC .GetObject (c .CTX , c .Bucket , key , minio.GetObjectOptions {})
70
+ if expiresAt , ok := objInfo .UserMetadata ["expires-at" ]; ok {
71
+ expTime , err := time .Parse (time .RFC3339 , expiresAt )
72
+ if err == nil && time .Now ().After (expTime ) {
73
+ // Object has expired, delete it and return not found
74
+ _ = c .Del (key ) // Ignore delete error
75
+ return "" , redis .Nil
76
+ }
77
+ }
78
+
79
+ object , err := c .mc .GetObject (c .ctx , c .bucket , key , minio.GetObjectOptions {})
44
80
if err != nil {
45
81
return "" , err
46
82
}
47
83
48
84
var val any
49
-
50
85
if err := json .NewDecoder (object ).Decode (& val ); err != nil {
51
86
return "" , err
52
87
}
@@ -63,12 +98,11 @@ func (c *CacheClientS3) Get(key string) (string, error) {
63
98
}
64
99
65
100
func (c * CacheClientS3 ) Del (key string ) error {
66
- return c .MC .RemoveObject (c .CTX , c .Bucket , key , minio.RemoveObjectOptions {
101
+ return c .mc .RemoveObject (c .ctx , c .bucket , key , minio.RemoveObjectOptions {
67
102
ForceDelete : true ,
68
103
})
69
104
}
70
105
71
106
func (c * CacheClientS3 ) Scan (key string , action func (context.Context , string ) error ) error {
72
-
73
107
return nil
74
108
}
0 commit comments