Skip to content

chore: add backed reader, writer and pipe implementation #19147

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 15 commits into
base: main
Choose a base branch
from

Conversation

ibetitsmike
Copy link
Contributor

@ibetitsmike ibetitsmike commented Aug 4, 2025

Fixes: #18101

This PR introduces a new backedpipe package that provides reliable bidirectional byte streams over unreliable network connections. The implementation includes:

  • BackedPipe: Orchestrates a reader and writer to provide transparent reconnection and data replay
  • BackedReader: Handles reading with automatic reconnection, blocking reads when disconnected
  • BackedWriter: Maintains a ring buffer of recent writes for replay during reconnection
  • RingBuffer: Efficient circular buffer implementation for storing data

The package enables resilient connections by tracking sequence numbers and replaying missed data after reconnection. It handles connection failures gracefully, automatically reconnecting and resuming data transfer from the appropriate point.

Copy link
Contributor Author

ibetitsmike commented Aug 4, 2025

@ibetitsmike ibetitsmike changed the title backed reader, writer and pipe implementation chore: add backed reader, writer and pipe implementation Aug 5, 2025
@ibetitsmike ibetitsmike force-pushed the mike/immortal-streams-backed-base branch from 9dd9c4a to 3223bf9 Compare August 5, 2025 08:46
@ibetitsmike ibetitsmike requested a review from spikecurtis August 5, 2025 09:36
@ibetitsmike ibetitsmike force-pushed the mike/immortal-streams-backed-base branch 2 times, most recently from d2ee08d to 27da7ef Compare August 7, 2025 11:18
@ibetitsmike ibetitsmike force-pushed the mike/immortal-streams-backed-base branch 3 times, most recently from 16abe05 to dde9516 Compare August 12, 2025 21:21
Copy link
Contributor

@spikecurtis spikecurtis left a comment

Choose a reason for hiding this comment

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

Not done with my review, but taking a break and wanted to send you comments so far.

Copy link
Contributor

@spikecurtis spikecurtis left a comment

Choose a reason for hiding this comment

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

Another batch of comments.

I haven't really looked at BackedPipe yet, but I think maybe it would be better to wait for the comments I've made so far to be resolved.

@ibetitsmike ibetitsmike force-pushed the mike/immortal-streams-backed-base branch from 7468299 to b2188f9 Compare August 15, 2025 00:51
@ibetitsmike ibetitsmike marked this pull request as ready for review August 15, 2025 08:50
@ibetitsmike ibetitsmike force-pushed the mike/immortal-streams-backed-base branch from 45558ec to 064514e Compare August 19, 2025 06:52
separate channels for writer/reader errors
moved to an interface for reconnection
coordination logic for closing a pipe
@ibetitsmike ibetitsmike force-pushed the mike/immortal-streams-backed-base branch from 95dc01a to 85c505d Compare August 20, 2025 12:38

// Update the generation on reader and writer for error reporting
bp.reader.SetGeneration(bp.connGen)
bp.writer.SetGeneration(bp.connGen)
Copy link
Contributor

Choose a reason for hiding this comment

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

You should set both of these during the Reconnect calls. With it like this, the Reconnect can finish and unblock reads/writes, which could error before you set the generation here, and then get ignored, hanging the pipe.

// Get current writer sequence number to send to remote
writerSeqNum := bp.writer.SequenceNum()

conn, readerSeqNum, err := bp.reconnector.Reconnect(bp.ctx, writerSeqNum)
Copy link
Contributor

Choose a reason for hiding this comment

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

This is backwards. You need to send the reader sequence number to the remote. The point of the sequence numbers is to inform the other side how much data we successfully read, so that it can replay from that number.

func NewBackedPipe(ctx context.Context, reconnector Reconnector) *BackedPipe {
pipeCtx, cancel := context.WithCancel(ctx)

errorChan := make(chan ErrorEvent, 10) // Buffered for async error reporting
Copy link
Contributor

Choose a reason for hiding this comment

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

What's the deal with 10? Like, why is that the right size for this buffer?

In general, I'd encourage you to consider anything other than 0 or 1 to be suspicious. There are legit uses for other numbers, but generally only if we are "buffering" to smooth out spiky usage.

}()

// Wait for read to start
testutil.RequireReceive(ctx, t, readStarted)
Copy link
Contributor

Choose a reason for hiding this comment

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

readStarted doesn't actually verify that the Read call has started, since it happens on line 121 and read doesn't happen until line 123. As such it doesn't really add anything to this test and should get removed.

// Read is still blocked, which is what we want
return !br.Connected()
}
}, testutil.WaitShort, testutil.IntervalMedium)
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't understand why this is wrapped in Eventually --- the reader has never connected at this point, so br.Connected() == true should be a test failure, not a retry. The other branch of the select is also a test failure.

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.

Indestructible IDE Connections (No disconnects when you re-open laptop)
2 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy