Skip to content

Improve task cancellation flow & lifecycle management#19

Closed
ThangKM wants to merge 5 commits intoanthony1810:mainfrom
ThangKM:cancellation_flow
Closed

Improve task cancellation flow & lifecycle management#19
ThangKM wants to merge 5 commits intoanthony1810:mainfrom
ThangKM:cancellation_flow

Conversation

@ThangKM
Copy link
Collaborator

@ThangKM ThangKM commented Mar 8, 2026

Improve task cancellation flow & lifecycle management

Summary

This PR enhances the cancellation and lifecycle management across CancelBag, StreamProducer, and ScreenActionStore.

Changes

CancelBag

  • Auto-cleanup of completed tasks — A new watch() method awaits each task's result and removes it from storage upon completion, preventing unbounded growth of the cancellers dictionary.
  • AnyHashable identifiers — Task identifiers are now AnyHashable instead of String, allowing actions (or any Hashable type) to be used directly as cancellation keys.
  • Optional bag parameterstore(in:) now accepts an optional CancelBag?, making it more ergonomic when a cancel bag may not be present.
  • isEmpty / count properties — Expose the current number of tracked tasks for inspection and testing.
  • Added documentation comments throughout.

StreamProducer

  • Extract StreamStorage — Moved continuation storage into a dedicated final class StreamStorage with a deinit that automatically finishes all streams, ensuring cleanup when the producer is deallocated.
  • Deprecate nonIsolatedFinish() — Marked as deprecated since streams now auto-finish on deallocation.

ScreenActionStore

  • Simplified protocol — Removed associatedtype AScreenState and binding(state:). The protocol now only requires receive(action:).
  • nonisolatedReceive(action:canceller:) — New default extension method that dispatches an action from a nonisolated context, optionally storing the task in a CancelBag using the action itself as the cancellation identifier.

Tests

  • Added testWatchTaskCompletedRemoveCancellerFromStorage verifying that completed tasks are automatically removed from the bag.

Commit Message

refactor: improve CancelBag lifecycle, extract StreamStorage, and simplify ScreenActionStore

- CancelBag: auto-remove completed tasks via watch(), add isEmpty/count,
  accept AnyHashable identifiers, make bag parameter optional
- StreamProducer: extract StreamStorage class with deinit cleanup,
  deprecate nonIsolatedFinish()
- ScreenActionStore: replace binding(state:) with receive(action:),
  add nonisolatedReceive helper with CancelBag support
- Add CancelBagTests for auto-removal of completed tasks

…plify ScreenActionStore

- CancelBag: auto-remove completed tasks via watch(), add isEmpty/count,
  accept AnyHashable identifiers, make bag parameter optional
- StreamProducer: extract StreamStorage class with deinit cleanup,
  deprecate nonIsolatedFinish()
- ScreenActionStore: replace binding(state:) with receive(action:),
  add nonisolatedReceive helper with CancelBag support
- Add CancelBagTests for auto-removal of completed tasks
@ThangKM ThangKM requested a review from anthony1810 March 8, 2026 05:14
@ThangKM ThangKM closed this Mar 15, 2026
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