Skip to content

Buffer emissions for async iterable integrity in Poll#792

Open
afshin wants to merge 3 commits into
jupyterlab:mainfrom
afshin:buffered-iterator
Open

Buffer emissions for async iterable integrity in Poll#792
afshin wants to merge 3 commits into
jupyterlab:mainfrom
afshin:buffered-iterator

Conversation

@afshin

@afshin afshin commented Feb 17, 2026

Copy link
Copy Markdown
Member

This PR updates Poll#[Symbol.asyncIterator] with a buffered implementation that connects to the ticked signal for each iterator returned to a client, ensuring rapid schedule() calls no longer silently drop intermediate states.

Previously, the iterator read this.state directly on each yield. When schedule() was called multiple times before the consumer resumed, this._state was overwritten and only the last state was visible.

The implementation in this PR pushes every ticked emission into a per-iterator queue and yields from it in order. When the queue is empty, it awaits this.tick as a wake-up signal. Cleanup is handled in a finally block to guarantee the signal listener is disconnected on break, return, throw, or disposal.

This problem does not exist in Stream from @lumino/signaling because stream's async iterator is based off of a promise chain instead of being a push-based state machine like Poll. The yield paradigm is pull-based. So to bridge this gap naively like the original implementation in Poll meant silently dropping emissions that disappear with no error because the poll state is being overwritten before the next yield. Effectively, then, Stream has a functionally unbound queue (a linked list of promises) and Poll has a bound queue of 1000 emissions that can pile up if a client consumes yielded values slowly.

No new API surface, no type changes, no effect on Throttler/RateLimiter.

Normal single-tick-at-a-time polling behaves identically.


The added tests in the polling test suite will fail (timeout) on the main branch but will pass with these changes.

@afshin afshin self-assigned this Feb 17, 2026
@afshin afshin added the bug Something isn't working label Feb 17, 2026
@afshin afshin marked this pull request as ready for review February 17, 2026 14:15
@afshin afshin changed the title Buffer emissions for async iterable integrity Buffer emissions for async iterable integrity in Poll Feb 17, 2026
@afshin afshin requested a review from Copilot February 17, 2026 17:55

Copilot AI 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.

Pull request overview

Updates Poll#[Symbol.asyncIterator] to buffer ticked emissions per iterator, preventing rapid schedule() calls from overwriting intermediate states before a consumer resumes iteration.

Changes:

  • Reworked Poll#[Symbol.asyncIterator] to enqueue each ticked state and yield in FIFO order, with finally-based disconnect cleanup.
  • Added tests validating no dropped states under rapid schedule() calls, correct behavior after disposal, and unchanged behavior for one-tick-at-a-time polling.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
packages/polling/src/poll.ts Implements per-iterator buffering of ticked emissions and ensures signal disconnection on iterator termination.
packages/polling/tests/src/poll.spec.ts Adds regression and behavior tests covering rapid scheduling, disposal, and baseline iteration behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/polling/src/poll.ts Outdated
Comment thread packages/polling/src/poll.ts Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

2 participants