Skip to content

Conversation

@kalekseev
Copy link

@kalekseev kalekseev commented Oct 20, 2025

DISCLAIMER: FIX IMPLEMENTED BY LLM AGENT

fixes #530

The integrated strategy's output_stream() has a race condition where
output_finish_future can resolve before asynchronous stdout pushes
complete. on_stdout schedules output_accum:push() via nio.run(), so the
push does not execute until the scheduler resumes the task. When EOF arrives,
output_finish_future.set() ran synchronously and could beat the pending
pushes, causing stream() to return nil while buffered data still existed.

Fix by tracking in-flight stdout pushes and defer setting the finish future
until all scheduled pushes finish. This keeps the stream alive until all
buffered stdout has been delivered, eliminating the race in fast or
sandboxed environments (e.g. Nix builds, CI) where the issue reproduced.

Fixes the "integrated strategy streams output" regression on Linux when the
scheduler services the finish future before pending stdout writes.

Nix sandbox tests error:

Testing:        /build/source/tests/unit/client/strategies/integrated_spec.lua
Success ||      integrated strategy produces output
Success ||      integrated strategy returns exit code
Success ||      integrated strategy stops the job
Fail    ||      integrated strategy streams output
            ...-luajit2.1-nvim-nio-1.10.1-1/share/lua/5.1/nio/tests.lua:48: Test task failed with message:
            The coroutine failed with this message:
            ...ry.nvim-scm-1-unstable-scm-1/lua/luassert/assertions.lua:115: the 'equals' function requires a minimum of 2 arguments, got: 1
            stack traceback:
                [C]: in function 'error'
                ...lenary.nvim-scm-1-unstable-scm-1/lua/luassert/assert.lua:169: in function 'assert'
                ...ry.nvim-scm-1-unstable-scm-1/lua/luassert/assertions.lua:115: in function 'callback'
                ...lenary.nvim-scm-1-unstable-scm-1/lua/luassert/assert.lua:43: in function 'equal'
                .../source/tests/unit/client/strategies/integrated_spec.lua:58: in function <.../source/tests/unit/client/strategies/integrated_spec.lua:48>

            stack traceback:
                ...-luajit2.1-nvim-nio-1.10.1-1/share/lua/5.1/nio/tests.lua:48: in function <...-luajit2.1-nvim-nio-1.10.1-1/share/lua/5.1/nio/tests.lua:31>

Success ||      integrated strategy opens attach window

Success:        4
Failed :        1
Errors :        0

Copy link

@yeldiRium yeldiRium left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Random approval since I'm interested in this being merged.

The controlflow looks correct. Either the end of data finishes the output or the last returning nio.run finishes the output, at which point pending_output_tasks is guaranteed to be zero.
It keeps the previous behavior of only finishing the output after empty data was sent.
No notes.

@rcarriga
Copy link
Collaborator

This looks great thank you 😄 Can you remove the outer function and just put all of the required variables above the jobstart call? Best to keep all captured variables on one level instead of nesting

@kalekseev
Copy link
Author

Can you remove the outer function and just put all of the required variables above the jobstart call? Best to keep all captured variables on one level instead of nesting

@rcarriga done

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] Test fail on current version

3 participants