@@ -3,6 +3,7 @@ package sensorsabtest
33import (
44 "errors"
55 "fmt"
6+ utils2 "github.com/sensorsdata/sa-sdk-go/utils"
67 "reflect"
78 "strconv"
89 "sync"
@@ -16,9 +17,10 @@ import (
1617// 用户的试验缓存
1718var experimentCache = lru .New (4096 )
1819var experimentLock = sync.Mutex {}
20+ var experimentTime = lru .New (4096 )
1921
2022// $ABTestTrigger 事件缓存
21- var eventsCache = lru .New (4096 )
23+ var eventsTime = lru .New (4096 )
2224var eventsLock = sync.Mutex {}
2325
2426// 插件版本号标记位
@@ -58,12 +60,24 @@ func loadExperimentFromNetwork(sensors *SensorsABTest, distinctId string, isLogi
5860
5961func loadExperimentFromCache (sensors * SensorsABTest , distinctId string , isLoginId bool , requestParam beans.RequestParam , isTrack bool ) (error , beans.Experiment ) {
6062 var experiment beans.Experiment
61- experiments , ok := loadExperimentCache (distinctId , isLoginId , requestParam .CustomIDs )
62- if experiments != nil || ok {
63- experiment = filterExperiment (requestParam , experiments .([]beans.Experiment ))
63+ var isRequestNetwork = false
64+ idKey := getExperimentKey (distinctId , requestParam .CustomIDs , isLoginId )
65+ if isExperimentExpired (idKey , sensors .config .ExperimentCacheTime ) {
66+ idKey := getExperimentKey (distinctId , requestParam .CustomIDs , isLoginId )
67+ // 进行清理缓存
68+ experimentCache .Remove (idKey )
69+ isRequestNetwork = true
70+ } else {
71+ experiments , ok := loadExperimentCache (idKey )
72+ if experiments != nil || ok {
73+ experiment = filterExperiment (requestParam , experiments .([]beans.Experiment ))
74+ }
75+ if experiments == nil || ! ok || experiment .AbtestExperimentId == "" {
76+ isRequestNetwork = true
77+ }
6478 }
6579
66- if experiments == nil || ! ok || experiment . AbtestExperimentId == "" {
80+ if isRequestNetwork {
6781 // 从网络请求试验
6882 experiments , err := requestExperimentOnNetwork (sensors .config .APIUrl , distinctId , isLoginId , requestParam )
6983 if err != nil {
@@ -73,7 +87,7 @@ func loadExperimentFromCache(sensors *SensorsABTest, distinctId string, isLoginI
7387 }
7488
7589 // 缓存试验
76- saveExperiment2Cache (distinctId , isLoginId , requestParam . CustomIDs , experiments , sensors . config . ExperimentCacheTime )
90+ saveExperiment2Cache (idKey , experiments )
7791 // 筛选试验
7892 experiment = filterExperiment (requestParam , experiments )
7993 }
@@ -120,19 +134,18 @@ func trackABTestEvent(distinctId string, isLoginId bool, experiment beans.Experi
120134 if sensors .config .SensorsAnalytics .C == nil {
121135 return
122136 }
123-
124137 // 是白名单,则不触发 $ABTestTrigger 事件
125138 if experiment .IsWhiteList {
126139 return
127140 }
128-
141+ idEvent := getEventKey ( distinctId , customIDs , experiment )
129142 // 如果在缓存中,则不触发 $ABTestTrigger 事件
130- _ , ok := loadEventFromCache ( distinctId , customIDs , experiment )
143+ ok := isEventExistAndNotExpired ( idEvent , sensors . config . EventCacheTime )
131144 if ok {
132145 return
133146 }
134147
135- saveEvent2Cache (distinctId , customIDs , experiment , sensors )
148+ saveEvent2Cache (idEvent , sensors )
136149 if properties == nil {
137150 properties = map [string ]interface {}{
138151 "$abtest_experiment_id" : experiment .AbtestExperimentId ,
@@ -149,7 +162,6 @@ func trackABTestEvent(distinctId string, isLoginId bool, experiment beans.Experi
149162 isFirstEvent = false
150163 lastTimeEvent = currentTime
151164 }
152-
153165 err := sensors .sensorsAnalytics .Track (distinctId , "$ABTestTrigger" , properties , isLoginId )
154166 if err != nil {
155167 fmt .Println ("$ABTestTrigger track failed, error : " , err )
@@ -160,55 +172,51 @@ func trackABTestEvent(distinctId string, isLoginId bool, experiment beans.Experi
160172// 初始化缓存大小
161173func initCache (config beans.ABTestConfig ) {
162174 if config .EventCacheSize != 0 {
163- eventsCache = lru .New (config .EventCacheSize )
175+ eventsTime = lru .New (config .EventCacheSize )
164176 }
165177
166178 if config .ExperimentCacheSize != 0 {
167179 experimentCache = lru .New (config .ExperimentCacheSize )
180+ experimentTime = lru .New (config .ExperimentCacheSize )
168181 }
169182}
170183
171184// 从缓存读取 $ABTestTrigger
172- func loadEventFromCache ( distinctId string , customIDs map [ string ] interface {}, experiment beans. Experiment ) ( interface {}, bool ) {
185+ func isEventExistAndNotExpired ( idEvent string , timeout time. Duration ) bool {
173186 eventsLock .Lock ()
174187 defer eventsLock .Unlock ()
175- idEvent := getEventKey (distinctId , customIDs , experiment )
176- return eventsCache .Get (idEvent )
188+ lastTime , ok := eventsTime .Get (idEvent )
189+ if ok {
190+ return (utils2 .NowMs () - lastTime .(int64 )) < int64 (timeout * time .Minute / time .Millisecond )
191+ }
192+
193+ return false
177194}
178195
179196// 保存 $ABTestTrigger 到缓存中
180- func saveEvent2Cache (distinctId string , customIDs map [ string ] interface {}, experiment beans. Experiment , sensors * SensorsABTest ) {
197+ func saveEvent2Cache (idEvent string , sensors * SensorsABTest ) {
181198 // 缓存 $ABTestTrigger 事件
182199 if sensors .config .EnableEventCache {
183200 eventsLock .Lock ()
184201 defer eventsLock .Unlock ()
185- idEvent := getEventKey (distinctId , customIDs , experiment )
186- eventsCache .Add (idEvent , experiment )
187- // 进行清理缓存
188- removeCache (idEvent , func (id string ) {
189- eventsCache .Remove (id )
190- }, sensors .config .EventCacheTime )
202+ eventsTime .Remove (idEvent )
203+ eventsTime .Add (idEvent , utils2 .NowMs ())
191204 }
192205}
193206
194207// 从缓存读取试验
195- func loadExperimentCache (distinctId string , isLoginId bool , customIds map [ string ] interface {} ) (interface {}, bool ) {
208+ func loadExperimentCache (idKey string ) (interface {}, bool ) {
196209 experimentLock .Lock ()
197210 defer experimentLock .Unlock ()
198- idKey := getExperimentKey (distinctId , customIds , isLoginId )
199211 return experimentCache .Get (idKey )
200212}
201213
202214// 保存试验到缓存
203- func saveExperiment2Cache (distinctId string , isLoginId bool , customIds map [ string ] interface {}, experiments []beans.Experiment , timeout time. Duration ) {
215+ func saveExperiment2Cache (idKey string , experiments []beans.Experiment ) {
204216 experimentLock .Lock ()
205217 defer experimentLock .Unlock ()
206- idKey := getExperimentKey (distinctId , customIds , isLoginId )
207218 experimentCache .Add (idKey , experiments )
208- // 进行清理缓存
209- removeCache (idKey , func (id string ) {
210- experimentCache .Remove (id )
211- }, timeout )
219+ experimentTime .Add (idKey , utils2 .NowMs ())
212220}
213221
214222func castValue (defaultValue interface {}, variables beans.Variables ) (interface {}, error ) {
@@ -252,22 +260,6 @@ func buildRequestParam(distinctId string, isLoginId bool, requestParam beans.Req
252260 return params
253261}
254262
255- // 清理缓存
256- func removeCache (idExperiment string , removeCache func (id string ), timeout time.Duration ) {
257- go func () {
258- var d time.Duration
259- if timeout == 0 {
260- d = 24 * time .Hour
261- } else {
262- d = timeout * time .Minute
263- }
264- t := time .NewTicker (d )
265- defer t .Stop ()
266- <- t .C
267- removeCache (idExperiment )
268- }()
269- }
270-
271263// 拼接缓存唯一标识
272264func getEventKey (distinctId string , customIds map [string ]interface {}, experiment beans.Experiment ) string {
273265 return distinctId + "$" + utils .MapToJson (customIds ) + "$" + experiment .AbtestExperimentId
@@ -276,3 +268,11 @@ func getEventKey(distinctId string, customIds map[string]interface{}, experiment
276268func getExperimentKey (distinctId string , customIds map [string ]interface {}, isLoginId bool ) string {
277269 return distinctId + "$" + utils .MapToJson (customIds ) + "$" + strconv .FormatBool (isLoginId )
278270}
271+
272+ func isExperimentExpired (idKey string , timeout time.Duration ) bool {
273+ lastTime , ok := experimentTime .Get (idKey )
274+ if ok {
275+ return (utils2 .NowMs () - lastTime .(int64 )) > int64 (timeout * time .Minute / time .Millisecond )
276+ }
277+ return false
278+ }
0 commit comments