@@ -23,16 +23,37 @@ class Predis implements Memoize
2323 */
2424 private $ refresh ;
2525
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+
2640 /**
2741 * Sets the predis client.
2842 *
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
3146 */
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+ ) {
3453 $ this ->client = $ client ;
3554 $ this ->refresh = $ refresh ;
55+ $ this ->refreshPercent = $ refreshPercent ;
56+ $ this ->runtimeMultiplier = $ runtimeMultiplier ;
3657 }
3758
3859 /**
@@ -51,19 +72,37 @@ public function memoizeCallable(string $key, callable $compute, int $cacheTime =
5172 {
5273 if (!$ this ->refresh ) {
5374 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+
5486 $ cached = $ this ->client ->get ($ key );
5587 if ($ cached !== null ) {
5688 $ data = json_decode ($ cached , true );
5789 return $ data ['result ' ];
5890 }
5991 } catch (\Exception $ e ) {
60- return call_user_func ( $ compute );
92+ return $ this -> getData ( $ key , $ compute, $ cacheTime );
6193 }
6294 }
6395
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 );
64102 $ result = call_user_func ($ compute );
103+ $ runtime = microtime (true ) - $ start ;
65104
66- $ this ->cache ($ key , json_encode (['result ' => $ result ]), $ cacheTime );
105+ $ this ->cache ($ key , json_encode (['result ' => $ result ]), $ cacheTime, $ runtime );
67106
68107 return $ result ;
69108 }
@@ -77,10 +116,11 @@ public function memoizeCallable(string $key, callable $compute, int $cacheTime =
77116 *
78117 * @return void
79118 */
80- private function cache (string $ key , string $ value , int $ cacheTime = null )
119+ private function cache (string $ key , string $ value , int $ cacheTime = null , float $ runtime )
81120 {
82121 try {
83122 $ this ->client ->set ($ key , $ value );
123+ $ this ->client ->set ("{$ key }.runtime " , $ runtime );
84124
85125 if ($ cacheTime !== null ) {
86126 $ this ->client ->expire ($ key , $ cacheTime );
0 commit comments