Skip to content

fix: scope native serial callbacks with MakeCallback - #243

Open
DragonWork wants to merge 2 commits into
serialport:mainfrom
DragonWork:fix/windows-async-callbacks
Open

DragonWork wants to merge 2 commits into
serialport:mainfrom
DragonWork:fix/windows-async-callbacks

Conversation

@DragonWork

@DragonWork DragonWork commented Sep 9, 2026 •

Copy link
Copy Markdown

Use MakeCallback() with an AsyncContext for Unix poller events and Windows read/write completions, including error paths. This prevents stalled nextTick/Promise continuations and preserves async context.

Preserves @Azq2's original commit from #239, followed by explicit async contexts and Windows support. Listener ordering (#240) is unchanged.

Linux/Node 26.8.2: native timing/context check, build, typecheck and 74 existing tests pass (2 skipped). Windows and macOS runtime testing is still needed.

@DragonWork
DragonWork force-pushed the fix/windows-async-callbacks branch from 932084a to 42279d6 Compare September 9, 2026 23:55
@DragonWork DragonWork changed the title fix: deliver Windows serial callbacks with MakeCallback fix: scope native serial callbacks with MakeCallback Sep 9, 2026
@DragonWork
DragonWork force-pushed the fix/windows-async-callbacks branch from 42279d6 to 3fbc715 Compare September 10, 2026 00:12
@Azq2

Azq2 commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Project rip :(

@DragonWork

Copy link
Copy Markdown
Author

Maybe someone (or better a group of devs) fork it and maintain the project. Or the original codeowner comes back. Let‘s hope for the best.

Comment thread src/poller.cpp
dashersw added a commit to geastack/cli that referenced this pull request Oct 15, 2026
@serialport/bindings-cpp completes Windows reads and writes on its own
thread and calls back into JavaScript from a uv_async handle with a plain
napi Call. Since Node.js 26.4 nothing drains the microtask queue after such
a call (nodejs/node#66158), so the promise the binding resolves continues
only when some other macrotask runs. On Windows every GEADEV command waited
for the next timer or console line: the USB app update timed out and fell
back to the ROM downloader (BOOT), and a chatty app stalled on a console
the host had stopped draining.

Until the binding scopes its callbacks (serialport/bindings-cpp#243),
loadSerialport wraps the native read/write so each callback queues a
setImmediate, after which Node drains microtasks. It has to run before
load-bindings.js promisifies them, so `gea doctor` loads serialport through
it too. Writes on Node 26.7 went from 2 s timeouts to 0-1 ms; neon (3.9 MB)
installs over a running reel through the app in 54 s, as on Node 24.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dashersw added a commit to geastack/cli that referenced this pull request Oct 15, 2026
@serialport/bindings-cpp completes Windows reads and writes on its own
thread and calls back into JavaScript from a uv_async handle with a plain
napi Call. Since Node.js 26.4 nothing drains the microtask queue after such
a call (nodejs/node#66158), so the promise the binding resolves continues
only when some other macrotask runs. On Windows every GEADEV command waited
for the next timer or console line: the USB app update timed out and fell
back to the ROM downloader (BOOT), and a chatty app stalled on a console
the host had stopped draining.

Until the binding scopes its callbacks (serialport/bindings-cpp#243),
loadSerialport wraps the native read/write so each callback queues a
setImmediate, after which Node drains microtasks. It has to run before
load-bindings.js promisifies them, so `gea doctor` loads serialport through
it too. Writes on Node 26.7 went from 2 s timeouts to 0-1 ms; neon (3.9 MB)
installs over a running reel through the app in 54 s, as on Node 24.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants