One process per tax ID (CNPJ or CPF) for NFeDistribuicaoDFe.
The library does not persist ult_nsu — the host does (AD-002). This process
owns the poll loop, a process label for Observer, and the hand-off of each
page to the caller's :handler.
Handler contract
:handler is required: a poller with nowhere to deliver is a no-op. It is
a one-arity function or an mfa/0 (the page is prepended to the extra
args), invoked in the poller process with a SefazNfe.DistDFe.t/0 page. Its
return value owns the cursor:
{:ok, ult_nsu}— continue from the cursor the host committed:ok— continue frompage.ult_nsuas returned by SEFAZ:stop— stop the poller normally (the child is:transient, so the supervisor leaves it down)
Delivery is at-least-once: the handler runs before the cursor moves, so
a handler that raises crashes the poller and the supervisor restarts it at the
cursor last given to start_link/1. DistDFe documents are idempotent by NSU,
so a replay is cheaper than a silent gap.
Scheduling
The child is :transient, not the :permanent default: a handler answering
:stop exits :normal and must stay down, while a crash still restarts at
the last cursor.
Three things shape the next delay. A page whose cursor still trails maxNSU
has a backlog — DistDFe answers around 50 documents per call — so it drains
after @catch_up instead of a whole interval. A page carrying cStat 656
(consumo indevido) backs off for an hour, because the AN blocks the tax ID
for that long and retrying sooner only renews the block. Every delay then
gets up to 10% of jitter, always later and never earlier, so that thousands
of pollers started by one release boot do not hit the AN in lockstep.
A transport error keeps the cursor and simply waits for the next tick; the library never retries DistDFe in a tight loop.
Logging
A multi-tenant host polls third-party tax IDs and DistDFe accepts CPF, so a raw identifier in a log line is personal data piling up (LGPD). Failures name the poller by the last four characters only, which is enough to tell two apart during an incident.
Options
:tax_id(required) — CNPJ (14) or CPF (11) of the interested party:uf(required) — the querying party's own state, sent ascUFAutor:cert(required) —SefazNfe.Certificate.t/0:handler(required) — see above:environment—:homologation(default) or:production:ult_nsu— starting cursor, default"0":interval—Duration.t/0between polls, default 5 minutes:fetch— one-arity fetch function, default&SefazNfe.dist_dfe/1. The seam that keepsmix testoff the network, and the hook for a host that wraps the call in its own circuit breaker.
Summary
Functions
Returns a specification to start this module under a supervisor.
Types
@type page() :: SefazNfe.DistDFe.t()
Functions
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec start_link(keyword()) :: GenServer.on_start()