Amarula.RetryCache.ReadOnly (amarula v0.4.1)
View SourceA read-only Amarula.RetryCache adapter backed by your message store.
Use this when your application already persists the messages it sends (an
outbox, an event log, a DB table). Pointing the retry cache at that store means
Amarula keeps no second copy — no ETS table, no DETS file, no max_entries
to size — and the retry path reads straight from what you already have.
You own writes; Amarula only reads. This adapter implements no write side at
all — it does not define the optional put/4 callback, so Amarula never even
attempts a write, and never evicts or deletes anything in your store. It is
your data. When a recipient asks the server for a retry, Amarula calls your
get with the msg_id and expects the original message back so it can
re-encrypt and resend it.
Usage
Pass a :get function fn profile, msg_id -> {:ok, entry} | :error end:
Amarula.new(%{
profile: :primary,
retry_cache:
{Amarula.RetryCache.ReadOnly,
get: fn _profile, msg_id ->
case MyApp.Outbox.fetch(msg_id) do
{:ok, %{to: jid, proto: %Amarula.Protocol.Proto.Message{} = m}} ->
{:ok, %{recipient_jid: jid, message: m}}
:error ->
:error
end
end}
})The returned map needs :recipient_jid (the wire JID the message went to) and
:message (the original %Amarula.Protocol.Proto.Message{}). Return the message
exactly as it was sent — a re-serialized or transformed copy may not match
what the recipient is retrying against. Return :error if you no longer have it
(e.g. past your own retention); Amarula then simply can't resend, which is the
same outcome as a built-in cache miss.
Why a function, not a module
For the common "wrap my store" case a closure is the whole adapter. If you need
more (per-profile state, a pooled connection), implement the Amarula.RetryCache
behaviour directly instead — this module is just the convenient shape.