Skip to content

fix(safe-operations): share one fallback AbortSignal across a withBoundedParallel batch (#221) - #403

Merged
Jaydbrown merged 2 commits into
mainfrom
fix/221-bounded-parallel-shared-signal
Aug 31, 2026
Merged

fix(safe-operations): share one fallback AbortSignal across a withBoundedParallel batch (#221)#403
Jaydbrown merged 2 commits into
mainfrom
fix/221-bounded-parallel-shared-signal

Conversation

@Jaydbrown

Copy link
Copy Markdown
Contributor

Rewrite of #382 on a main-repo branch (so CI runs — the fork PR had no
checks). Same fix, same test.

Problem

withBoundedParallel (lib/safe-operations.ts) built the AbortSignal
handed to each handler as options?.signal ?? new AbortController().signal
inside the worker loop. When the caller passes no outer signal, this
allocated a fresh AbortController for every item and threw it away
immediately — nothing kept a reference to call .abort(), so
signal.aborted stayed false forever and per-item cancellation silently
never worked (#221).

Fix

Compute the fallback signal once per call, before the loop starts. Every
item in an outer-signal-less call now gets the same AbortSignal instance.
It is still not externally abortable without an API change (returning the
controller / an onAbort hook) — out of scope for this bug — but it is a
coherent shared object rather than a dead one manufactured per item.

The only real call site, components/stream/BulkWithdrawButton.tsx, always
passes its own options.signal and never reads the handler's third
parameter, so this is fully backward compatible; the handler type
(signal: AbortSignal, never undefined) is unchanged.

Test

lib/safe-operations.test.ts — new 'shares a single fallback signal across items when no outer signal is provided': three items, asserts all three
receive the exact same AbortSignal instance (the old code gave each a
distinct dead one). Existing signal tests unchanged.

Local npm install is not possible in this environment (the lockfile
registry is unreachable here), so verification is via CI on this branch.

Closes #221

…ndedParallel batch

withBoundedParallel built the signal handed to each handler as
`options?.signal ?? new AbortController().signal` *inside* the worker loop.
With no outer signal, that allocated a fresh AbortController per item and
discarded it immediately — nothing held a reference to call .abort(), so
signal.aborted was permanently false and per-item cancellation silently
never worked (#221).

Compute the fallback signal once per call, before the loop. Every item in
an outer-signal-less call now receives the same AbortSignal instance. It's
still not externally abortable without an API change (out of scope here),
but it's a coherent shared object rather than a dead one built per item.

The one real call site (components/stream/BulkWithdrawButton.tsx) always
passes its own options.signal and ignores the handler's third parameter,
so this is fully backward compatible.

Closes #221
@Jaydbrown

Copy link
Copy Markdown
Contributor Author

CI here fails at the npm ci step, not on this change — main fails identically on every recent commit. package-lock.json has two pre-existing problems:

  1. @conduit-protocol/sdk resolves to git+ssh://git@github.com/conduit-protocol/conduit-sdk.git — that repo was renamed to streamFi-sdk, so the install can't fetch it.
  2. ~30 packages are resolved against https://registry.npmmirror.com/... (a regional mirror) instead of registry.npmjs.org, which the CI runner can't reach.

Both need a package-lock.json regeneration on main before any app PR can go green. The code change in this PR is a 1-line fix plus a regression test; the diff is small enough to review directly.

@Jaydbrown

Copy link
Copy Markdown
Contributor Author

Root cause filed as #404.

@mhikel66

Copy link
Copy Markdown
Contributor

Superseded — #382 (the original) was merged as ef1b61d, so this rewrite is now redundant and conflicts with main. Leaving it open for a maintainer to close.

@Jaydbrown
Jaydbrown merged commit 2d1fdf0 into main Aug 31, 2026
0 of 2 checks passed
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.

Bug: withBoundedParallel gives each item a dead AbortSignal that can never fire when no outer signal is passed

2 participants