pyinvoke / invoke

Pythonic task management & command execution.
http://pyinvoke.org
BSD 2-Clause "Simplified" License
4.31k stars 365 forks source link

How do I read the current output with asynchronous without waiting for the process to finish? #951

Open red8888 opened 1 year ago

red8888 commented 1 year ago

FYI created an SO post too: https://stackoverflow.com/questions/76491927/how-do-i-read-the-current-output-with-asynchronous-without-waiting-for-the-proce/76492139#76492139

Its documented, but are there any complete examples and snippets for how to use asynchronous=True?

I usually have to look through github issues when trying to find full example snippets to stuff, but maybe I'm just missing this in the docs.

Im doing this

@task
def my_cmd(ctx: Context):
    invoke_promise = ctx.run(
        "while true; do echo running forevah; sleep 2; done", warn=True, hide=False, echo=True, asynchronous=True
    )

This throws an error

print(invoke_promise)

Traceback (most recent call last):
  File "/usr/local/bin/myproject", line 8, in <module>
    sys.exit(program.run())
  File "/usr/local/lib/python3.10/site-packages/invoke/program.py", line 384, in run
    self.execute()
  File "/usr/local/lib/python3.10/site-packages/invoke/program.py", line 569, in execute
    executor.execute(*self.tasks)
  File "/usr/local/lib/python3.10/site-packages/invoke/executor.py", line 129, in execute
    result = call.task(*args, **call.kwargs)
  File "/usr/local/lib/python3.10/site-packages/invoke/tasks.py", line 127, in __call__
    result = self.body(*args, **kwargs)
  File "/workspaces/myproject/myproject/tasks/mytask.py", line 479, in my_cmd
    print(invoke_promise)
  File "/usr/local/lib/python3.10/site-packages/invoke/runners.py", line 1475, in __str__
    if self.exited is not None:
AttributeError: 'Promise' object has no attribute 'exited'

This hangs forever until the process exits print(invoke_promise.join())

What method is there on the returned promise object to just get the current output of the running background process that was started?

I want to be able to:

  1. Just see the current output so far without waiting for it to finish
  2. Be able to read the output of the currently running process and choose to manually kill it if I want
red8888 commented 1 year ago

Based on this github issue I think I found a solution: https://github.com/pyinvoke/invoke/issues/689

@task
def my_cmd(ctx: Context):
    invoke_promise = ctx.run(
        "while true; do echo running forevah; sleep 2; done", warn=True, hide=False, echo=True, asynchronous=True
    )

    import time
    time.sleep(10)  # ie do a bunch of work in the foreground

    # Check the current output of backgroud process
    current_output = invoke_promise.runner.stdout

    # ... parse current output and do stuff
    # Based on current output decide if and when to kill it 
    invoke_promise.runner.kill()

Is this how I should be doing this?