Skip to content

voice: the docs promise backpressure, the socket side drops a slow client by count (DISPATCH_QUEUE = 64) #601

Description

@mmeyerlein

The contradiction

docs/cell-types.md describes the voice cell's interim path as backpressure by design: nothing is dropped, a slow listener delays the sender. The code says something narrower. VoiceIoShared::send_to hands each frame to the client task through a bounded DISPATCH_QUEUE (64) with try_send, and when that queue is full it gives the connection up — counter-based, deliberate, without a clock. So the colony-side lane really is backpressure (the router waits on a full mailbox), but the socket side is not: a client that cannot drain 64 frames loses its session and every frame after that.

Measured (2026-09-06, GH #600)

  • voice_t5_behaviour::backpressure_loses_nothing on a loaded host (loadavg 9–14 on 8 cores, three colonies live): 147, 159 and 204 of 500 interims reached the listener; the rest were never sent because the client task lost the race against the emitter and the session was discarded.
  • The old test never measured backpressure at all: the listener mailbox ran at the default 1000 and swallowed 500 messages without the router ever waiting. The rewritten test (counter-based, mailbox 4, 50 interims, 5 green runs at 0.47–0.75 s under loadavg 14) proves the colony-side promise and stays below the queue that breaks the socket-side one.

The decision

Which contract is the voice cell's?

  1. "A client that falls behind is dropped, loudly, by count." Then docs/cell-types.md and templates/voice/README.md say so, name the queue depth as the number that decides, and the drop becomes an error lane emission with error_code instead of a silent discard.
  2. "Backpressure all the way to the socket." Then send_to awaits the queue (or the client task applies the same bounded wait the router does), a stalled client stalls the emitter, and the watchdog/timeout story for a stuck socket has to be written.

Either way documentation and code must say the same thing afterwards. Not to be built tonight; Marcus decides.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    rulingNeeds a decision by the maintainer before it is built

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions