Skip to content

Add run_command completion callbacks - #428

Open
zxc1031408077 wants to merge 1 commit into
ParallelSSH:masterfrom
zxc1031408077:codex/issue-275-run-command-callback
Open

zxc1031408077 wants to merge 1 commit into
ParallelSSH:masterfrom
zxc1031408077:codex/issue-275-run-command-callback

Conversation

@zxc1031408077

Copy link
Copy Markdown

Summary

  • add optional completion callbacks to single-host and parallel run_command
  • support callback_extra_args and invoke the callback after command completion
  • add coverage for native and SSH clients, documentation, and changelog entries

Testing

  • pytest (24 passed)
  • flake8
  • python -m compileall
  • Sphinx documentation build

Closes #275

@codecov

codecov Bot commented Oct 19, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.47%. Comparing base (97a7414) to head (35d8631).

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #428      +/-   ##
==========================================
- Coverage   99.53%   99.47%   -0.06%     
==========================================
  Files          18       18              
  Lines        1703     1714      +11     
==========================================
+ Hits         1695     1705      +10     
- Misses          8        9       +1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@pkittenis pkittenis left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for the interest and PR. Left some comments on handling greenlets spawned as callbacks.

return HostOutput(host, None, None, None, exception=ex, alias=alias)
host_out = HostOutput(host, None, None, None, exception=ex, alias=alias)
if callback is not None:
spawn(self._run_command_callback, host_out, callback, callback_extra_args)

@pkittenis pkittenis Oct 20, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is not the right approach here. Callback should be executed by wait_finished directly by SSHClient. Parallel client should not need changes other than to pass-through callback and args when calling ParallelSSHClient.run_command. There is no need to spawn more greenlets just for callback.

ParallelClient.run_command -> [many] SSHClient.run_command -> [each SSHClient] run_command + callback

Use HostOutput to keep track of per-host-cmd callbacks, and use them in ParallelSSHClient._join.

_timeout = read_timeout if read_timeout else timeout
host_out = self._make_host_output(channel, encoding, _timeout, fully_qualified_command=_command)
if callback is not None:
spawn(self._run_command_callback, host_out, callback, callback_extra_args)

@pkittenis pkittenis Oct 20, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should not be spawning callback in greenlet here. This causes issues with race conditions, and is not the right approach.

SSHClient should run callback directly without a greenlet in its wait_finished function, ie after command has finished executing. SSHClient.run_command should not need changes. SSHClient callback should be in wait_finished.

Comment thread tests/test_callbacks.py
self.assertEqual(callback_args, [host_output, 'extra'])

# Give spawned greenlets a chance to finish before the test tears down.
sleep(0)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should not be necessary, is a race condition. See review comments.

If the callback does something that takes time to finish, eg gevent.sleep(1), a race condition occurs.

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.

Callback support for run_command in parallel and single clients

2 participants