Skip to content

Configure delivery classes for data channel#160

Open
wrangelvid wants to merge 1 commit into
PulseBeamDev:mainfrom
wrangelvid:feat/data-reliability-classes
Open

Configure delivery classes for data channel#160
wrangelvid wants to merge 1 commit into
PulseBeamDev:mainfrom
wrangelvid:feat/data-reliability-classes

Conversation

@wrangelvid

@wrangelvid wrangelvid commented Jul 17, 2026

Copy link
Copy Markdown

This should add the remaining delivery classes. Let me know what you think.

Summary by CodeRabbit

  • New Features

    • Added configurable data-channel delivery modes: lossy, semi-reliable, and reliable ordered.
    • Added reliable delivery buffering and automatic retry handling when channels are temporarily unavailable.
    • Data topics now expose their configured delivery semantics.
  • Bug Fixes

    • Reliable messages are now delivered in order without drops under normal channel backpressure.
  • Tests

    • Added coverage for delivery-mode mapping and reliable ordered message forwarding.

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The change adds configurable data-channel delivery classes, propagates reliability and ordering through topic metadata, buffers reliable packets during RTC backpressure, and tests reliable ordered forwarding in the simulator.

Changes

Data-channel delivery semantics

Layer / File(s) Summary
Delivery contracts and topic configuration
pulsebeam/src/track.rs, pulsebeam-agent/src/agent/driver.rs, pulsebeam-agent/src/agent/mod.rs
Public delivery classes map to channel reliability and ordering, topic metadata records the selected class, and agent topic declarations accept optional delivery settings while preserving default behavior.
Reliable forwarding and backlog lifecycle
pulsebeam/src/participant/core.rs
ParticipantCore queues reliable packets under backpressure, flushes them through buffered-amount events and polling, and clears backlog state on channel cleanup.
Reliable ordered delivery validation
pulsebeam-simulator/src/tests/data_channel.rs
A simulator test publishes sequential reliable-ordered payloads and verifies contiguous ordered receipt.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Publisher
  participant ParticipantCore
  participant RTCDataChannel
  participant Subscriber
  Publisher->>ParticipantCore: publish reliable packet
  ParticipantCore->>RTCDataChannel: write packet
  RTCDataChannel-->>ParticipantCore: signal backpressure
  ParticipantCore->>ParticipantCore: queue packet in ReliableBacklog
  ParticipantCore->>RTCDataChannel: flush queued packets
  RTCDataChannel->>Subscriber: deliver ordered payload
Loading

Suggested reviewers: lherman-cs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding configurable delivery classes for data channels.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pulsebeam-agent/src/agent/driver.rs (1)

837-860: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Reject delivery changes for an already-declared topic.

The early return reuses the existing channel without verifying delivery. For example, declaring a topic as lossy and then requesting ReliableOrdered succeeds but retains the lossy configuration. Store and compare the existing delivery settings, or explicitly recreate the channel.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pulsebeam-agent/src/agent/driver.rs` around lines 837 - 860, Update
ensure_data_topic to compare the requested delivery with the existing topic’s
delivery settings before returning its ChannelId. Reject mismatches with the
appropriate AgentError, while preserving the current reuse behavior when
delivery matches; apply this consistently to both publish and subscribe topic
maps.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pulsebeam-agent/src/agent/driver.rs`:
- Around line 112-129: The ReliableOrdered send path must retain publisher
messages when channel writes return Ok(false) under backpressure. Update the
relevant forwarding/write logic near DeliveryClass::ReliableOrdered and the
referenced publisher-write section to queue locally and retry rejected writes,
matching the existing forwarding-side behavior while preserving immediate
handling of successful writes and errors.

In `@pulsebeam/src/participant/core.rs`:
- Around line 221-224: Update flush_reliable_backlog and its callers to return
distinct Flushed, Blocked, and Closed outcomes instead of a boolean; preserve
each outcome through channel-missing or closed handling, and change the packet
path around enqueue_reliable so the current packet is re-enqueued only for
Blocked, not for Closed.

---

Outside diff comments:
In `@pulsebeam-agent/src/agent/driver.rs`:
- Around line 837-860: Update ensure_data_topic to compare the requested
delivery with the existing topic’s delivery settings before returning its
ChannelId. Reject mismatches with the appropriate AgentError, while preserving
the current reuse behavior when delivery matches; apply this consistently to
both publish and subscribe topic maps.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 914ac1e0-e333-44b9-8822-712641926268

📥 Commits

Reviewing files that changed from the base of the PR and between 86fb303 and 60d316b.

📒 Files selected for processing (5)
  • pulsebeam-agent/src/agent/driver.rs
  • pulsebeam-agent/src/agent/mod.rs
  • pulsebeam-simulator/src/tests/data_channel.rs
  • pulsebeam/src/participant/core.rs
  • pulsebeam/src/track.rs

Comment on lines +112 to +129
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum DeliveryClass {
#[default]
Lossy,
SemiReliable {
retransmits: u16,
},
ReliableOrdered,
}

impl DeliveryClass {
fn channel_settings(self) -> (bool, Reliability) {
match self {
Self::Lossy => (false, Reliability::MaxRetransmits { retransmits: 0 }),
Self::SemiReliable { retransmits } => {
(false, Reliability::MaxRetransmits { retransmits })
}
Self::ReliableOrdered => (true, Reliability::Reliable),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Buffer locally backpressured ReliableOrdered publisher writes.

ReliableOrdered configures SCTP reliability, but the existing send path discards ch.write(...) == Ok(false). Under RTC backpressure, accepted publisher messages therefore vanish before reaching the reliable channel. Queue and retry these writes, as the forwarding side does.

Also applies to: 324-329

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pulsebeam-agent/src/agent/driver.rs` around lines 112 - 129, The
ReliableOrdered send path must retain publisher messages when channel writes
return Ok(false) under backpressure. Update the relevant forwarding/write logic
near DeliveryClass::ReliableOrdered and the referenced publisher-write section
to queue locally and retry rejected writes, matching the existing
forwarding-side behavior while preserving immediate handling of successful
writes and errors.

Comment on lines +221 to +224
if !self.flush_reliable_backlog(cid) {
self.enqueue_reliable(cid, pkt.to_vec());
return;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Distinguish backpressure from terminal flush failure.

false means both “temporarily blocked” and “channel missing/closed.” The caller consequently re-enqueues the current packet after flush_reliable_backlog has removed or closed the channel, recreating stale backlog state. Return separate Flushed, Blocked, and Closed outcomes, and enqueue only for Blocked.

Also applies to: 244-276

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pulsebeam/src/participant/core.rs` around lines 221 - 224, Update
flush_reliable_backlog and its callers to return distinct Flushed, Blocked, and
Closed outcomes instead of a boolean; preserve each outcome through
channel-missing or closed handling, and change the packet path around
enqueue_reliable so the current packet is re-enqueued only for Blocked, not for
Closed.

@lherman-cs

lherman-cs commented Jul 17, 2026

Copy link
Copy Markdown
Member

@wrangelvid, as mentioned #155, a reliable and ordered mode, closer to "exactly once" guarantee, unfortunately, is harder than it looks. Most of the complexity comes from the fact that SFU terminates SCTP on the edge, and the relationship is many-to-many, meaning we need a way to also route each packet internally in reliable and ordered mode too. I want to be extra careful in claiming that we support this, when in reality, people can experience implicit data loss.

Currently, the system is only single-node. But we want this to be able to scale horizontally as well, so deployment is easier. Even with a single node, communications between cores don't have this reliable and ordered delivery guarantee. It doesn't make sense to make it reliable and ordered, as this will lead to backpressure & potentially a deadlock.

Alternatively, a "reliable" and "ordered" mode is best implemented at the application level on the client side, wrapping the current "unreliable" transport layer. The client is the ideal place to enforce this guarantee because it decouples session state from socket life. If a network migration occurs, or if an SFU node fails over, any transport-level protocol state (like native SCTP) is destroyed, resulting in immediate data loss and sequence resets.

I also typically see people using MQTT alongside WebRTC in IOT because there's plenty of mature infrastructure for this.

TL;DR: It’s not a flat no, but if we support a "reliable and ordered" channel, it needs to actually hold up cluster-wide. Right now, claiming we support it risks hidden data loss during node failovers or inter-core communication, where forcing strict ordering would just trigger backpressure and deadlocks.

@lherman-cs
lherman-cs force-pushed the main branch 2 times, most recently from eedc5b1 to 730d253 Compare July 24, 2026 23:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants