+2
CHANGELOG.md
+2
CHANGELOG.md
···
38
38
39
39
- `mix atex.lexicons` now adds `@moduledoc false` to generated modules to stop
40
40
them from automatically cluttering documentation.
41
+
- `Atex.IdentityResolver.Cache.ETS` now uses ConCache instead of ETS directly,
42
+
with a 1-hour TTL for cached identity information.
41
43
42
44
## [0.6.0] - 2025-11-25
43
45
+35
-22
lib/atex/identity_resolver/cache/ets.ex
+35
-22
lib/atex/identity_resolver/cache/ets.ex
···
1
1
defmodule Atex.IdentityResolver.Cache.ETS do
2
+
@moduledoc """
3
+
ConCache-based implementation for Identity Resolver caching.
4
+
5
+
Stores identity information (DID and handle mappings) with a 1-hour TTL.
6
+
Uses two separate cache entries per identity to allow lookups by either DID or handle.
7
+
"""
8
+
2
9
alias Atex.IdentityResolver.Identity
3
10
@behaviour Atex.IdentityResolver.Cache
4
11
use Supervisor
5
12
6
-
@table :atex_identities
13
+
@cache :atex_identities_cache
14
+
@ttl_ms :timer.hours(1)
7
15
8
16
def start_link(opts) do
9
-
Supervisor.start_link(__MODULE__, opts)
17
+
Supervisor.start_link(__MODULE__, opts, name: __MODULE__)
10
18
end
11
19
12
20
@impl Supervisor
13
21
def init(_opts) do
14
-
:ets.new(@table, [:set, :public, :named_table])
15
-
Supervisor.init([], strategy: :one_for_one)
22
+
children = [
23
+
{ConCache,
24
+
[
25
+
name: @cache,
26
+
ttl_check_interval: :timer.minutes(5),
27
+
global_ttl: @ttl_ms
28
+
]}
29
+
]
30
+
31
+
Supervisor.init(children, strategy: :one_for_one)
16
32
end
17
33
18
34
@impl Atex.IdentityResolver.Cache
19
35
@spec insert(Identity.t()) :: Identity.t()
20
36
def insert(identity) do
21
-
# TODO: benchmark lookups vs match performance, is it better to use a "composite" key or two inserts?
22
-
:ets.insert(@table, {{identity.did, identity.handle}, identity})
37
+
ConCache.put(@cache, {:did, identity.did}, identity)
38
+
ConCache.put(@cache, {:handle, identity.handle}, identity)
23
39
identity
24
40
end
25
41
26
42
@impl Atex.IdentityResolver.Cache
27
43
@spec get(String.t()) :: {:ok, Identity.t()} | {:error, atom()}
28
44
def get(identifier) do
29
-
lookup(identifier)
45
+
case ConCache.get(@cache, {:did, identifier}) do
46
+
nil ->
47
+
case ConCache.get(@cache, {:handle, identifier}) do
48
+
nil -> {:error, :not_found}
49
+
identity -> {:ok, identity}
50
+
end
51
+
52
+
identity ->
53
+
{:ok, identity}
54
+
end
30
55
end
31
56
32
57
@impl Atex.IdentityResolver.Cache
33
58
@spec delete(String.t()) :: :noop | Identity.t()
34
59
def delete(identifier) do
35
-
case lookup(identifier) do
60
+
case get(identifier) do
36
61
{:ok, identity} ->
37
-
:ets.delete(@table, {identity.did, identity.handle})
62
+
ConCache.delete(@cache, {:did, identity.did})
63
+
ConCache.delete(@cache, {:handle, identity.handle})
38
64
identity
39
65
40
66
_ ->
41
67
:noop
42
-
end
43
-
end
44
-
45
-
defp lookup(identifier) do
46
-
case :ets.match(@table, {{identifier, :_}, :"$1"}) do
47
-
[] ->
48
-
case :ets.match(@table, {{:_, identifier}, :"$1"}) do
49
-
[] -> {:error, :not_found}
50
-
[[identity]] -> {:ok, identity}
51
-
end
52
-
53
-
[[identity]] ->
54
-
{:ok, identity}
55
68
end
56
69
end
57
70
end