MCPcopy Create free account
hub / github.com/NodeDB-Lab/nodedb / fan_out

Function fan_out

nodedb-cluster/src/distributed_array/scatter.rs:109–162  ·  view source on GitHub ↗

Send `req_bytes` to every shard listed in `params` and collect responses. Each shard RPC runs concurrently via `FuturesUnordered`. Per-shard timeouts are enforced by `tokio::time::timeout`. The circuit breaker is checked before each call and updated on success/failure. Any shard error causes the whole fan-out to return `Err` — the coordinator decides whether to retry. Returns `Vec<(shard_id, res

(
    params: &FanOutParams,
    opcode: u32,
    req_bytes: &[u8],
    dispatch: &Arc<dyn ShardRpcDispatch>,
    circuit_breaker: &CircuitBreaker,
)

Source from the content-addressed store, hash-verified

107///
108/// Returns `Vec<(shard_id, response_payload_bytes)>` in arrival order.
109pub async fn fan_out(
110 params: &FanOutParams,
111 opcode: u32,
112 req_bytes: &[u8],
113 dispatch: &Arc<dyn ShardRpcDispatch>,
114 circuit_breaker: &CircuitBreaker,
115) -> Result<Vec<(u32, Vec<u8>)>> {
116 if params.shard_ids.is_empty() {
117 return Ok(Vec::new());
118 }
119
120 // Build one future per shard and collect via FuturesUnordered for
121 // true concurrency (no sequential .await loop).
122 let mut futs = futures::stream::FuturesUnordered::new();
123
124 for &shard_id in &params.shard_ids {
125 // Circuit-breaker gate: treat shard_id as the peer identifier.
126 circuit_breaker.check(shard_id as u64)?;
127
128 let env = VShardEnvelope::new(
129 msg_type_from_opcode(opcode)?,
130 params.source_node,
131 0, // target_node resolved by the dispatch impl
132 shard_id,
133 req_bytes.to_vec(),
134 );
135 let timeout_ms = params.timeout_ms;
136 let dispatch = Arc::clone(dispatch);
137 let cb_shard = shard_id;
138
139 futs.push(async move {
140 match call_with_wrong_owner_retry(&dispatch, env, timeout_ms).await {
141 Ok(resp) => Ok((cb_shard, resp.payload)),
142 Err(e) => Err((cb_shard, e)),
143 }
144 });
145 }
146
147 let mut results = Vec::with_capacity(params.shard_ids.len());
148 while let Some(outcome) = futs.next().await {
149 match outcome {
150 Ok((shard_id, payload)) => {
151 circuit_breaker.record_success(shard_id as u64);
152 results.push((shard_id, payload));
153 }
154 Err((shard_id, e)) => {
155 circuit_breaker.record_failure(shard_id as u64);
156 return Err(e);
157 }
158 }
159 }
160
161 Ok(results)
162}
163
164/// Send a distinct payload to each shard and collect responses.
165///

Calls 10

msg_type_from_opcodeFunction · 0.85
is_emptyMethod · 0.45
checkMethod · 0.45
to_vecMethod · 0.45
pushMethod · 0.45
lenMethod · 0.45
nextMethod · 0.45
record_successMethod · 0.45
record_failureMethod · 0.45

Tested by

no test coverage detected