-
Notifications
You must be signed in to change notification settings - Fork 0
/
timeout_cache.ex
81 lines (62 loc) · 1.44 KB
/
timeout_cache.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
defmodule Klotho.Support.TimeoutCache do
@moduledoc false
use GenServer
# API
def start_link() do
GenServer.start_link(__MODULE__, [])
end
def set(pid, key, value, timeout) do
GenServer.call(pid, {:set, key, value, timeout})
end
def get(pid, key) do
GenServer.call(pid, {:get, key})
end
# gen_server
def init([]) do
{:ok, %{}}
end
def handle_call({:set, key, value, timeout}, _from, state) do
new_st =
state
|> maybe_delete(key)
|> put_new(key, value, timeout)
{:reply, :ok, new_st}
end
def handle_call({:get, key}, _from, state) do
{:reply, get_value(state, key), state}
end
def handle_info({:timeout, ref, key}, state) do
new_st = maybe_delete_timeout(state, key, ref)
{:noreply, new_st}
end
# private
defp maybe_delete(state, key) do
case state do
%{^key => {_value, ref}} ->
Klotho.cancel_timer(ref)
Map.delete(state, key)
_ ->
state
end
end
defp put_new(state, key, value, timeout) do
ref = Klotho.start_timer(timeout, self(), key)
Map.put(state, key, {value, ref})
end
defp maybe_delete_timeout(state, key, ref) do
case state do
%{^key => {_value, ^ref}} ->
Map.delete(state, key)
_ ->
state
end
end
defp get_value(state, key) do
case state do
%{^key => {value, _ref}} ->
{:ok, value}
_ ->
:not_found
end
end
end