fed-sx-m2: Step 8a — delivery_worker skeleton + 17 tests
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 55s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 55s
next/kernel/delivery_worker.erl is the gen_server-per-peer
delivery queue per design §13.4. Step 8a lands the skeleton:
pure-functional state shape + enqueue / drain / deliver_one
helpers + backoff schedule + gen_server wrapper. No retry
timer wiring yet (Step 8b), no persist projection yet (8c),
no outbox dispatch wiring yet (8d), no httpc BIF yet (8e), no
live HTTP yet (8f).
State shape (pure):
[{peer, PeerId},
{pending, [Activity, ...]}, %% FIFO queue
{attempts, [{Cid, AttemptCount}]}, %% per-cid retry count
{dead_letter, [Activity, ...]},
{dispatch_fn, fun/1 | undefined}]
Pure-functional API:
new/1
pending/1, peer/1
enqueue_pure/3 — append to FIFO
drain_pure/1 — attempt every queued; returns
{NewState, DeliveredCids, RetryCids}
deliver_one_pure/2 — single dispatch via :dispatch_fn
Backoff schedule (§13.4): 30s / 5m / 30m / 6h / 24h then dead_letter
backoff_for/1 — attempt -> seconds | dead_letter
schedule_for/1 — attempt -> {retry_in, Sec} | dead_letter
gen_server (registered under peer-id atom):
start_link/1, start_link/2(PeerId, DispatchFn)
stop/1
enqueue/2 — sync call
flush/1 — drain + reply with {ok, Delivered, Retry}
pending_srv/1
set_dispatch_fn/2 — swap dispatch in flight
dispatch_fn is a caller-supplied 1-arity fun so tests can stub the
HTTP POST. Step 8f will plug in a closure over httpc:request/4
without touching the queue logic.
17/17 in next/tests/delivery_worker.sh covering:
- new/peer/pending base cases
- enqueue_pure FIFO append
- drain_pure no-dispatch -> retry, queue intact
- drain_pure ok dispatch -> queue empties + delivered list
- drain_pure failing dispatch -> queue intact + retry list
- deliver_one_pure {ok, Cid} and {error, _, no_dispatch_fn}
- backoff_for slot values match §13.4
- backoff_for >=6 returns dead_letter
- schedule_for wraps the slot or dead_letter
- gen_server start_link + enqueue + pending_srv
- gen_server flush with ok dispatch (delivered)
- gen_server flush with failing dispatch (queue kept)
- gen_server set_dispatch_fn in-flight swap
Conformance 761/761.
This commit is contained in:
@@ -536,15 +536,38 @@ a dead-letter list visible via `/admin/dead-letter`.
|
||||
|
||||
**Deliverables:**
|
||||
|
||||
- `delivery_worker.erl`: gen_server per-peer queue with `enqueue/2`
|
||||
and a private retry loop.
|
||||
- Backoff schedule: 30s / 5m / 30m / 6h / 24h then dead-letter.
|
||||
- Delivery state stored as a projection (`delivery-state`) so it
|
||||
survives kernel restarts.
|
||||
- `outbox:publish/2` augmented: after `log:append`, dispatch to the
|
||||
delivery worker for each delivery-set entry.
|
||||
- HTTP client: extend the existing native httpc primitive to
|
||||
carry signed envelope bytes + the right Content-Type.
|
||||
- [x] **8a** — `delivery_worker.erl` skeleton: pure-functional
|
||||
state shape `[{peer, _}, {pending, [_]}, {attempts, [{Cid, N}]},
|
||||
{dead_letter, [_]}, {dispatch_fn, _}]` plus
|
||||
`enqueue_pure/3`, `drain_pure/1`, `deliver_one_pure/2` and the
|
||||
backoff schedule (`backoff_for/1`, `schedule_for/1`) matching
|
||||
§13.4 (30s / 5m / 30m / 6h / 24h then dead-letter).
|
||||
gen_server wrapper with `start_link/1,2`, `enqueue/2`, `flush/1`,
|
||||
`pending_srv/1`, `set_dispatch_fn/2`. dispatch_fn is a
|
||||
caller-supplied 1-arity fun so tests can stub the HTTP POST;
|
||||
Step 8f plugs in the live httpc call without touching the
|
||||
queue logic. No actual HTTP yet; no retry timer wiring yet.
|
||||
17/17 in `delivery_worker.sh`.
|
||||
- [ ] **8b** — Retry / backoff scheduler. Wire `schedule_for/1`
|
||||
into a private retry loop: `flush/1` returns deliveries that
|
||||
failed; the worker schedules a self-cast via Erlang `after`
|
||||
timer for the next retry slot. Tests fake-time via a Cfg
|
||||
`:now_fn`.
|
||||
- [ ] **8c** — Delivery-state projection so the queue survives
|
||||
kernel restart. New `next/kernel/delivery_state.erl` fold maps
|
||||
enqueue / delivered / failed events to the worker's persistent
|
||||
shape.
|
||||
- [ ] **8d** — `outbox:publish/2` dispatches each delivery-set
|
||||
entry to the matching worker. The worker is created lazily on
|
||||
first delivery to a peer.
|
||||
- [ ] **8e** — `httpc:request/4` BIF wrapper in
|
||||
`lib/erlang/runtime.sx` (the briefing's allowed scope
|
||||
exception for Step 8). Marshalling: SX dict ↔ Erlang proplist
|
||||
shape with `{ok, Status, Headers, Body}` / `{error, Reason}`.
|
||||
- [ ] **8f** — Real HTTP dispatch through the BIF + content-type
|
||||
wiring. dispatch_fn for live use becomes a closure over the
|
||||
peer URL that calls `httpc:request/4` with the signed envelope
|
||||
bytes as the body.
|
||||
|
||||
**Tests:**
|
||||
|
||||
@@ -867,6 +890,18 @@ proceed.
|
||||
|
||||
Newest first.
|
||||
|
||||
- **2026-06-07** — Step 8a: delivery_worker skeleton.
|
||||
`next/kernel/delivery_worker.erl` with pure-functional state +
|
||||
enqueue / drain / deliver_one + backoff schedule (30s / 5m /
|
||||
30m / 6h / 24h then dead-letter, per design §13.4). gen_server
|
||||
wrapper exposes the same APIs under the peer-id atom. dispatch
|
||||
is a caller-supplied `:dispatch_fn` fun — Step 8b layers the
|
||||
retry timer, Step 8c persists the queue, Step 8d wires
|
||||
`outbox:publish/2` to dispatch, Step 8e brings the
|
||||
`httpc:request/4` BIF (substrate exception per briefing), Step
|
||||
8f closes with live HTTP. 17/17 in `delivery_worker.sh`.
|
||||
Conformance 761/761.
|
||||
|
||||
- **2026-06-07** — Step 7c (closes Step 7): outbox-side
|
||||
delivery_set integration. `outbox:publish/2` computes the
|
||||
audience-resolved delivery set after sign + log and stashes
|
||||
|
||||
Reference in New Issue
Block a user