# `Slink.Dedup`
[🔗](https://github.com/wkirschbaum/slink/blob/v0.6.0/lib/slink/dedup.ex#L1)

Drops Slack's *retried* event deliveries so a handler never fires twice.

Slack re-sends an event (same `event_id`) when it doesn't see a timely ACK —
even though both transports ACK before the handler runs, a slow network or a
restart can still produce duplicates. This keeps a short-lived set of seen
keys (`{handler_module, event_id}`) in ETS; the dispatcher consults it
before dispatching.

It's a `set` ETS table owned by this process but read/written directly by
callers (so the dedup check never blocks on a GenServer). A periodic sweep
evicts entries past their TTL.

The table is node-local, so dedup is per-instance. Across a multi-node fleet
a retry can land on a different instance than the original delivery (Slack
load-balances Socket Mode connections, and an HTTP retry can hit a different
pod), and that instance won't recognise it. Retries are rare — both
transports ACK before the handler runs — so this is a best-effort safety net;
hard cross-instance dedup would need a shared store.

## Configuration

  * `config :slink, :dedup, true` — master switch (default `true`). When
    `false`, `seen?/1` always returns `false` and nothing is tracked.
  * `config :slink, :dedup_ttl_ms, 660_000` — how long a key is remembered
    (default 11 minutes). Slack retries a failed delivery immediately, after
    ~1 minute, and after ~5 minutes, so the default covers the whole schedule
    with margin.

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `seen?`

Whether `key` has been seen within the TTL; records it if not.

Returns `false` (and remembers `key`) the first time, `true` on a repeat.
Always `false` when dedup is disabled or the table isn't up yet, so a missing
dedup process fails open — never silently swallowing real events.

# `start_link`

---

*Consult [api-reference.md](api-reference.md) for complete listing*
