@steve02081504/fount-p2p 0.0.25 → 0.0.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -285,7 +285,6 @@ export async function processIncomingPartQueryRequest(wireContext, wire, request
285
285
 
286
286
  const selfHash = nodeHashOf()
287
287
  const exclude = new Set([selfHash, request.originNodeHash, String(peerId || '').trim().toLowerCase()].filter(Boolean))
288
- const neighbors = username ? await selectQueryNeighbors(username, exclude, dependencies) : []
289
288
  const forwardPayload = { ...request, ttl: nextTtl }
290
289
 
291
290
  /** @type {RelayPending} */
@@ -304,18 +303,25 @@ export async function processIncomingPartQueryRequest(wireContext, wire, request
304
303
  state,
305
304
  }
306
305
  state.relayPending.set(request.requestId, pending)
307
-
308
- let sent = 0
309
- for (const target of neighbors)
310
- if (await deliverQuery(target, 'part_query_req', forwardPayload, dependencies)) sent++
311
- pending.expected = sent
312
-
313
- if (sent === 0 || pending.received >= pending.expected) {
314
- flushRelayPending(pending)
315
- return
316
- }
317
-
306
+ // 先挂 hop 超时:勿等 select/deliver settle,否则 stuck send 永不 flush upstream(#13 同类)
318
307
  pending.timer = setTimeout(() => flushRelayPending(pending), resolvePartQueryHopTimeoutMs(request.ttl))
308
+
309
+ void (async () => {
310
+ try {
311
+ const neighbors = username ? await selectQueryNeighbors(username, exclude, dependencies) : []
312
+ if (pending.flushed) return
313
+ let sent = 0
314
+ for (const target of neighbors)
315
+ if (await deliverQuery(target, 'part_query_req', forwardPayload, dependencies)) sent++
316
+ if (pending.flushed) return
317
+ pending.expected = sent
318
+ if (sent === 0 || pending.received >= pending.expected)
319
+ flushRelayPending(pending)
320
+ }
321
+ catch {
322
+ if (!pending.flushed) flushRelayPending(pending)
323
+ }
324
+ })()
319
325
  }
320
326
 
321
327
  /**
@@ -353,6 +359,7 @@ export function handleIncomingPartQueryResponse(response, peerId = '', dependenc
353
359
 
354
360
  /**
355
361
  * 多跳查询:本地 handler + 网络回流(反向路径聚合);本地缓存命中则不广播。
362
+ * `timeoutMs` 端到端约束:select/deliver 挂起也不阻塞返回。
356
363
  * @param {string} username trust graph 上下文
357
364
  * @param {string} partpath part 路径
358
365
  * @param {string} kind 查询标签
@@ -420,14 +427,20 @@ export async function queryNetwork(username, partpath, kind, query, options = {}
420
427
 
421
428
  const selfHash = nodeHashOf()
422
429
  const exclude = new Set([selfHash, parsed.originNodeHash])
423
- const neighbors = await selectQueryNeighbors(username, exclude, options)
424
- let sent = 0
425
- for (const target of neighbors)
426
- if (await deliverQuery(target, 'part_query_req', parsed, options)) sent++
427
- bag.expected = sent
428
-
429
- if (sent === 0 || bag.received >= bag.expected)
430
- finishMultiWireWaiters(state.originWaits, parsed.requestId, '')
430
+ // await select/deliver:否则 timeout 已触发也要等扇出 settle(#13)
431
+ void (async () => {
432
+ try {
433
+ const neighbors = await selectQueryNeighbors(username, exclude, options)
434
+ let sent = 0
435
+ for (const target of neighbors)
436
+ if (await deliverQuery(target, 'part_query_req', parsed, options)) sent++
437
+ bag.expected = sent
438
+ if (sent === 0 || bag.received >= bag.expected)
439
+ finishMultiWireWaiters(state.originWaits, parsed.requestId, '')
440
+ }
441
+ catch { /* pending wait 超时负责 settle */ }
442
+ })()
443
+
431
444
  await waitPromise
432
445
  state.originBags.delete(parsed.requestId)
433
446
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@steve02081504/fount-p2p",
3
- "version": "0.0.25",
3
+ "version": "0.0.26",
4
4
  "description": "fount federation P2P layer — link, trust graph, mailbox, DAG, EVFS.",
5
5
  "keywords": [
6
6
  "network",
@@ -61,10 +61,11 @@ export function partInvokeErrorMessages(results) {
61
61
  /**
62
62
  * 向 trust-graph top-K 扇出 part_invoke,收集 part_invoke_response。
63
63
  * 调用方须已挂载 `attachPartWire`(否则收不到 response)。
64
+ * `timeoutMs` 端到端约束:fanout 挂起(discoverRoute / stuck send)也不阻塞返回。
64
65
  * @param {string} username trust graph 上下文
65
66
  * @param {string} partpath part 路径
66
67
  * @param {PartInvoke} invoke 调用体
67
- * @param {number} [timeoutMs=2500] 超时
68
+ * @param {number} [timeoutMs=2500] 端到端超时
68
69
  * @param {number} [maxResponses=6] 最多响应数
69
70
  * @returns {Promise<PartInvokeResponse[]>} 邻居 PartInvokeResponse(含 error)
70
71
  */
@@ -85,15 +86,16 @@ export async function collectPartInvokeResponses(username, partpath, invoke, tim
85
86
  pendingPartInvoke.set(requestId, { responses, finish, maxResponses, respondedPeers: new Set() })
86
87
  })
87
88
 
88
- const sent = await requireTrustGraphProvider(DEFAULT_TRUST_GRAPH_OWNER).fanoutToTopNodes(
89
+ // await fanout:否则 timeout 已触发也要等扇出 settle(#13)
90
+ void requireTrustGraphProvider(DEFAULT_TRUST_GRAPH_OWNER).fanoutToTopNodes(
89
91
  username,
90
92
  'part_invoke',
91
93
  buildPartInvokePayload(partpath, invoke, nodeHash, requestId),
92
94
  maxResponses,
93
- )
94
-
95
- const pending = pendingPartInvoke.get(requestId)
96
- if (pending && sent === 0) pending.finish()
95
+ ).then(sent => {
96
+ const pending = pendingPartInvoke.get(requestId)
97
+ if (pending && sent === 0) pending.finish()
98
+ }, () => { /* pending wait 超时负责 settle */ })
97
99
 
98
100
  return waitForResponses
99
101
  }