@@ -23,16 +23,37 @@ class Predis implements Memoize
23
23
*/
24
24
private $ refresh ;
25
25
26
+ /**
27
+ * The percentage of requests that check for refreshes
28
+ *
29
+ * @var int
30
+ */
31
+ private $ refreshPercent ;
32
+
33
+ /**
34
+ * The multiplier to use on runtime when deciding to do a refresh
35
+ *
36
+ * @var float
37
+ */
38
+ private $ runtimeMultiplier ;
39
+
26
40
/**
27
41
* Sets the predis client.
28
42
*
29
- * @param ClientInterface $client The predis client to use
30
- * @param boolean $refresh If true we will always overwrite cache even if it is already set
43
+ * @param ClientInterface $client The predis client to use
44
+ * @param boolean $refresh If true we will always overwrite cache even if it is already set
45
+ * @param int $refreshPercent The percentage of requests that check for refreshes
31
46
*/
32
- public function __construct (ClientInterface $ client , bool $ refresh = false )
33
- {
47
+ public function __construct (
48
+ ClientInterface $ client ,
49
+ bool $ refresh = false ,
50
+ int $ refreshPercent = 0 ,
51
+ float $ runtimeMultiplier = 3
52
+ ) {
34
53
$ this ->client = $ client ;
35
54
$ this ->refresh = $ refresh ;
55
+ $ this ->refreshPercent = $ refreshPercent ;
56
+ $ this ->runtimeMultiplier = $ runtimeMultiplier ;
36
57
}
37
58
38
59
/**
@@ -51,19 +72,37 @@ public function memoizeCallable(string $key, callable $compute, int $cacheTime =
51
72
{
52
73
if (!$ this ->refresh ) {
53
74
try {
75
+ if (rand (1 , 100 ) <= $ this ->refreshPercent ) {
76
+ // {$refreshPercent}% of requests should check to see if this key is almost expired.
77
+ // We don't want to check this on every call to preserve performance.
78
+ // Also, this functionality is only important for requests that have many concurrent calls.
79
+ $ runtime = $ this ->client ->get ("{$ key }.runtime " );
80
+ $ ttl = $ this ->client ->pttl ($ key ) / 1000 ;
81
+ if ($ runtime && $ runtime * $ this ->runtimeMultiplier > $ ttl ) {
82
+ return $ this ->getData ($ key , $ compute , $ cacheTime );
83
+ }
84
+ }
85
+
54
86
$ cached = $ this ->client ->get ($ key );
55
87
if ($ cached !== null ) {
56
88
$ data = json_decode ($ cached , true );
57
89
return $ data ['result ' ];
58
90
}
59
91
} catch (\Exception $ e ) {
60
- return call_user_func ( $ compute );
92
+ return $ this -> getData ( $ key , $ compute, $ cacheTime );
61
93
}
62
94
}
63
95
96
+ return $ this ->getData ($ key , $ compute , $ cacheTime );
97
+ }
98
+
99
+ private function getData (string $ key , callable $ compute , int $ cacheTime = null )
100
+ {
101
+ $ start = microtime (true );
64
102
$ result = call_user_func ($ compute );
103
+ $ runtime = microtime (true ) - $ start ;
65
104
66
- $ this ->cache ($ key , json_encode (['result ' => $ result ]), $ cacheTime );
105
+ $ this ->cache ($ key , json_encode (['result ' => $ result ]), $ cacheTime, $ runtime );
67
106
68
107
return $ result ;
69
108
}
@@ -77,10 +116,11 @@ public function memoizeCallable(string $key, callable $compute, int $cacheTime =
77
116
*
78
117
* @return void
79
118
*/
80
- private function cache (string $ key , string $ value , int $ cacheTime = null )
119
+ private function cache (string $ key , string $ value , int $ cacheTime = null , float $ runtime )
81
120
{
82
121
try {
83
122
$ this ->client ->set ($ key , $ value );
123
+ $ this ->client ->set ("{$ key }.runtime " , $ runtime );
84
124
85
125
if ($ cacheTime !== null ) {
86
126
$ this ->client ->expire ($ key , $ cacheTime );
0 commit comments