Skip to content

fix(bloc_concurrency): close droppable stream when source ends mid-event - #4829

Open
tonytonycoder11 wants to merge 1 commit into
felangel:masterfrom
tonytonycoder11:fix/droppable-close-on-done
Open

fix(bloc_concurrency): close droppable stream when source ends mid-event#4829
tonytonycoder11 wants to merge 1 commit into
felangel:masterfrom
tonytonycoder11:fix/droppable-close-on-done

Conversation

@tonytonycoder11

Copy link
Copy Markdown

Status

READY

Breaking Changes

NO

Description

droppable() uses a hand-written _ExhaustMapStreamTransformer whose output StreamController is never closed when the source event stream completes while a mapped event handler is still in flight.

  • The source onDone (() => mappedSubscription ?? controller.close()) intentionally defers closing while a mapped subscription is active, but
  • the mapped subscription's onDone (() => mappedSubscription = null) only clears the reference and never re-checks whether the source has already completed.

As a result the transformed stream never emits done: the subscription leaks and a Bloc/Cubit that is closed while a droppable event is being processed never completes. The sibling transformers all propagate source completion (sequentialasyncExpand, concurrentconcurrentAsyncExpand, restartableswitchMap), so droppable was the only outlier.

This tracks source completion with an isSourceDone flag and closes the output controller once the source is done and no event is in flight (extracted into a small maybeClose() helper so the completion condition lives in one place):

  • source completes while idle → close immediately (unchanged behavior);
  • source completes while an event is in flight → close once the mapped subscription's onDone fires.

There is no public API change and no change to event-dropping, cancellation, or idle-completion behavior. A regression test covering the source-completes-mid-event path is included (it fails on master and passes with this change); the existing suite stays green at 100% coverage.

Type of Change

  • ✨ New feature (non-breaking change which adds functionality)
  • 🛠️ Bug fix (non-breaking change which fixes an issue)
  • ❌ Breaking change (fix or feature that would cause existing functionality to change)
  • 🧹 Code refactor
  • ✅ Build configuration change
  • 📝 Documentation
  • 🗑️ Chore

droppable()'s hand-written _ExhaustMapStreamTransformer never closed its
output StreamController when the source stream completed while a mapped
event handler was still in flight, so the transformed stream never emitted
`done` (leaking the subscription and preventing a Bloc/Cubit closed
mid-event from ever completing).

Track source completion and close the output stream once the source is done
and no event is in flight, matching the completion propagation of the sibling
sequential/concurrent/restartable transformers. Adds a regression test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@codecov

codecov Bot commented Jul 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

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.

1 participant