Files
skills/docs/networking/drive/drive-mesh/src/scheduler/parallel-puller/parallel-puller.md
2026-05-29 08:20:56 +01:00

4.6 KiB

parallel-puller.ts

(no submodules)

Purpose

ParallelPuller is the chunk-fetch scheduler that turns "I want chunk N of file F" into a verified Uint8Array. The puller asks the PeerRegistry for ranked candidates, issues a request to the best peer, waits racingWindowMs, then issues parallel requests to the runners-up. The first response whose server signature verifies wins; the other in-flight attempts are aborted via a shared AbortController.

The puller is the mesh's primary trust enforcement point. Every byte returned from a transport flows through verifyChunkSig before the puller acknowledges success. A signature failure moves the offending peer to the registry's denylist with score = -Infinity and surfaces DriveMeshError(SIG_VERIFY_FAILED) — the orchestrator can choose to fall back to the server rather than retry on peers.

Features

  • Top-K candidate selection (default 3).
  • Racing-window staggered issuance (default 250 ms).
  • Shared AbortController short-circuits losing attempts.
  • Mandatory verifyChunkSig gate against the configured serverPubKey.
  • Bad-sig denylisting via registry.recordBadSig.
  • Non-signature failures update success / failure counters so ranking adapts.
  • maxParallelRequests global cap.

Usage: Basic Example

import { ParallelPuller } from "@suaveplan/drive-mesh/scheduler/parallel-puller";

const puller = new ParallelPuller({
    registry,
    transports: [httpsTransport],
    serverPubKey,
});
const bytes = await puller.pull("file-id-hex", 0);

Usage: Advanced Example

import { ParallelPuller } from "@suaveplan/drive-mesh/scheduler/parallel-puller";

const puller = new ParallelPuller({
    registry,
    transports: [webrtcTransport, httpsTransport],
    serverPubKey,
    racingWindowMs: 150,
    topK: 4,
    maxParallelRequests: 16,
    clock: fakeClock,
    onAttempt: (peerId, fileId, chunkId) =>
        log.debug("attempt", peerId, fileId, chunkId),
    onSuccess: (peerId, _f, _c, bytes, elapsedMs) =>
        log.info("served", peerId, bytes, elapsedMs),
    onBadSig: peerId => log.warn("denylisting", peerId),
});

const controller = new AbortController();
setTimeout(() => controller.abort(), 5_000);
try {
    const bytes = await puller.pull(fileId, chunkId, controller.signal);
} catch (err) {
    if (err instanceof DriveMeshError && err.code === DRIVE_MESH_CODES.ABORTED) {
        // caller-driven cancellation
    }
}

API Reference

  • class ParallelPuller:
    • constructor(options: ParallelPullerOptions).
    • pull(fileId, chunkId, signal?): Promise<Uint8Array>.
    • inflight: number (read-only) — in-flight request count.
  • ParallelPullerOptions:
    • registry, transports, serverPubKey (required).
    • maxParallelRequests? (default 8).
    • racingWindowMs? (default 250).
    • topK? (default 3).
    • clock?.
    • onAttempt?(peerId, fileId, chunkId).
    • onSuccess?(peerId, fileId, chunkId, bytes, elapsedMs).
    • onFailure?(peerId, fileId, chunkId, reason).
    • onBadSig?(peerId, fileId, chunkId).
  • Throws:
    • DRIVE_MESH.CHUNK_UNAVAILABLE — no candidate peers.
    • DRIVE_MESH.SIG_VERIFY_FAILED — winning peer returned bad sig.
    • DRIVE_MESH.TRANSPORT_FAILED — single-attempt transport failure.
    • DRIVE_MESH.ALL_PEERS_FAILED — every candidate failed.
    • DRIVE_MESH.ABORTED — caller-provided signal aborted.

Implementation Notes

firstSettled is hand-rolled rather than using Promise.any: Promise.any resolves on first success but does NOT abort losing attempts, leaving them in flight wastefully. The shared AbortController is the cancellation primitive — controller.abort() fires both when a winner appears and when the outer caller aborts.

SIG_VERIFY_FAILED short-circuits the "all peers failed" wrapping: the orchestrator distinguishes "every peer failed transport" (try server fallback) from "winning peer was Byzantine" (denylist + retry on a different peer). Re-wrapping the bad-sig error inside ALL_PEERS_FAILED would lose that distinction.

maxParallelRequests is enforced by a yielding micro-loop in #awaitSlot. The loop is bounded by the number of concurrent pull calls — drive-mesh issues pull from a small, controlled set of async contexts so the loop never spins indefinitely. Under heavier fan-in the orchestrator should queue requests in front of the puller rather than issuing every chunk concurrently.

Bad-sig denylist is permanent within the registry's denylist scope: session (default) clears on mesh.stop(), persistent survives. The puller does not concern itself with scope — the registry is the authority.