Skip to content

Cancelling one branch of a tee'd stream never finishes if other branch reads all chunks #1038

Description

@MattiasBuelens

When teeing a stream, if one branch is cancelled while the other branch is read until the end, then the cancel promise of the first branch never resolves.

Reproduction case

const readable = new ReadableStream({
    start(controller) {
        for (let chunk of ["a", "b", "c"]) {
            controller.enqueue(chunk);
        }
        controller.close();
    }
});
const [leftStream, rightStream] = readable.tee();

(async () => {
    const reader = leftStream.getReader();
    // Cancel the left branch immediately.
    console.log("left cancel start");
    let cancelPromise = reader.cancel();
    // The left branch never finishes cancelling.
    let cancelResult = await cancelPromise;
    console.log("left cancel done", cancelResult); // never reached
})();

(async () => {
    const reader = rightStream.getReader();
    // Read all chunks from the right branch.
    while (true) {
        const {value, done} = await reader.read();
        console.log("right read:", {value, done});
        if (done) break;
    }
    // The right branch has read all the chunks.
    let closedResult = await reader.closed;
    console.log("right closed", closedResult);
})();

Expected results

The left branch should finish cancelling once all chunks have been read from the original stream (as a result of the right branch pulling them).

Actual results

The left branch never finishes cancelling.

Investigation

Currently, the specification for ReadableStreamTee only resolves cancelPromise when both branches are cancelled. However, I believe this needs to happen when either both branches are cancelled, or when the last chunk has been pulled (i.e. during the "If done is true" step of pullAlgorithm).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions