Skip to main content

Module ack

Module ack 

Source
Expand description

Network fanout acknowledgement policy and result types.

Implements Gun.js ask-pattern semantics for multi-peer replication: a requester sends a Message::Put to the router, the router registers the put as a quorum-tracked write via Message::RegisterQuorum, the router fans the put out to peers, and tracks the per-peer acks until an AckPolicy quorum is satisfied.

§Wire format (Gun.js compatible)

Peer acks reuse the existing Put { in_response_to: Some(put_id), .. } wire — the @ field in serialized JSON. Quorum completion is signalled by a __quorum_met__ sentinel in the reply’s updated_nodes, with the ack count as the value. This mirrors the existing _ack/_err sentinel convention used by Node::put and Node::batch_put, so callers can use the same drain plumbing.

§Reserved sentinel prefix

__beam__ is the reserved prefix for wire-level sentinels. Existing:

  • __beam_replay_complete__ — emitted by map() replay to signal drain complete

New:

  • __quorum_met__ — emitted by Router when quorum threshold is reached

The __ prefix is filtered during normal data iteration (see Node::handle_put reserved-prefix handling), so these sentinels never collide with user data.

§Lifecycle

  Node::put_quorum(value, policy)
    ├── build Put, register oneshot in pending_puts
    ├── send Message::RegisterQuorum { put_id, requester, policy } to Router
    ├── send Message::Put(put) to Router
    │     ↓
    │   Router creates internal QuorumEntry for put_id
    │   Router::handle_put_relay fans out to peers (same as fire-and-forget)
    │     ↓
    │   Each peer eventually replies with Put { @: put_id, .. }
    │     ↓
    │   Router::handle_put sees Put.@, finds QuorumEntry, increments counter
    │   When counter >= policy.quorum → Router sends reply back to requester:
    │     Put { @: put_id, updated_nodes: { "__quorum_met__": ack_count } }
    └── requester's oneshot resolves with ReplicationStatus

§Why a sentinel, not a new Result variant

The codebase has converged on sentinel-drain as the canonical ack pattern (see feat/beam-redux-async-ack-and-drain branch):

  • _ack/_err sentinels for storage commit confirmation
  • __beam_replay_complete__ sentinel for replay drain

Adding __quorum_met__ keeps the drain plumbing DRY — the same pending_puts: Arc<RwLock<HashMap<String, oneshot::Sender<...>>>> map and tokio::time::timeout envelope that Node::put uses are reused for Node::put_quorum. Only the decoder differs: instead of looking for _ack/_err, put_quorum looks for __quorum_met__.

§Quorum policies

§Timeout

Default timeout matches Gun.js lack = 9000ms. Configurable via AckPolicy::with_timeout. On timeout the requester’s oneshot resolves with Err("put_quorum timed out") and the Router’s internal QuorumEntry is reaped lazily (removed on next access by another put for the same id, or by the Router’s periodic cleanup if added later).

§Design constraints

  • No new Message variant for the ack wire — reuses Put { in_response_to, .. } for ack routing
  • One new Message variant: RegisterQuorum — minimal struct with (put_id, requester_addr, policy); used by the Router to create the QuorumEntry before fan-out
  • Sentinel-driven completion__quorum_met__ in updated_nodes, matching the _ack/_err convention
  • No new dependency — uses existing std, tokio

Structs§

AckPolicy
Policy controlling how many peer acks satisfy a put_quorum request.
ReplicationStatus
Result of a successful put_quorum request.

Constants§

DEFAULT_QUORUM_TIMEOUT
Default timeout for quorum requests, matching Gun.js lack = 9000ms.
QUORUM_MET_SENTINEL
Reserved sentinel key emitted by the Router when quorum threshold is met.