@@ -29,39 +29,26 @@ def with_cache(hash_name, key, json: true)
29
29
30
30
# If the cache value is currently being computed, we bail out early and expect the client to
31
31
# re-request in a bit.
32
- #
33
- # If the value has been computing for longer than the cutoff, we assume the old computation
34
- # failed and compute it ourselves
35
- is_recomputing = false
36
- if cached
37
- if cached . start_with? "__computing__"
38
- date_string = cached . split ( "__computing__" ) [ 1 ]
39
- date = Date . parse ( date_string )
40
-
41
- if date < 3 . minute . ago . utc
42
- raise ApplicationController ::LockError
43
- else
44
- is_recomputing = true
45
- end
46
- else
47
- return cached
48
- end
32
+ if cached && !cached . start_with? ( "__computing__" )
33
+ return cached
49
34
end
35
+ # If the value is currently being computed, we fall back to trying to acquire the lock and then
36
+ # return the value from there once we have it.
50
37
51
38
# Lock the cache entry that we're trying to write to in order to ensure that we're not
52
39
# computing the same expensive value that some other worker is already computing
53
40
lock_key = "#{ hash_name } _#{ key } "
54
41
ret = nil
55
- $lock_manager. lock ( lock_key , 18502 ) do |locked |
42
+ $lock_manager. lock ( lock_key , 240000 ) do |locked |
56
43
if locked
57
44
begin
58
45
# It's possible someone else was computing this while we were waiting for the lock. If so, we
59
46
# just return that and avoid re-computing
60
47
refreshed_cached = get_cache hash_name , key
61
48
62
49
if cached != refreshed_cached
63
- if refreshed_cached . starts_with? "__computing__"
64
- # Someone else beat us to the lock and is re- computing the value, so we just let them do it
50
+ if refreshed_cached . starts_with? ( "__computing__" )
51
+ # The 4-minute window for computing that value has expired since their lock ran out. Maybe
65
52
$lock_manager. unlock ( locked )
66
53
raise ApplicationController ::LockError
67
54
end
@@ -72,14 +59,14 @@ def with_cache(hash_name, key, json: true)
72
59
end
73
60
74
61
# Create a placeholder value in the cache indicating that the value is currently being computed
75
- # and when the computation started
76
- now = Time . new
77
- date_string = now . strftime ( "%Y-%m-%d %H:%M:%S" )
78
- placeholder_val = "__computing__#{ date_string } "
79
- put_cache hash_name , key , placeholder_val , false
62
+ #
63
+ # We have exclusive access to this cache entry currently.
64
+ put_cache hash_name , key , "__computing__" , false
80
65
81
66
# Compute the new value while holding the lock, set it in the cache, and then drop the lock
82
67
ret = put_cache hash_name , key , yield , json
68
+ $lock_manager. unlock ( locked )
69
+ next
83
70
rescue ApplicationController ::NotFound
84
71
delete_cache hash_name , key
85
72
$lock_manager. unlock ( locked )
@@ -93,7 +80,6 @@ def with_cache(hash_name, key, json: true)
93
80
end
94
81
else
95
82
p "Failed to acquire a lock for key #{ lock_key } in the timeout period"
96
- $lock_manager. unlock ( locked )
97
83
raise ApplicationController ::LockError
98
84
end
99
85
end
0 commit comments