Skip to content

Commit

Permalink
Workaround for invoke silently failing on Windows (pyinvoke#683).
Browse files Browse the repository at this point in the history
There is a race condition between process_is_finished and has_dead_threads, at least on windows. The check for the process being finished returns False, then the stdio and stderr threads "die", so the process exists without a valid error code. Return code is None, then all the tasks abort without any error messages, even though the processes have completed successfully.

This happens so frequently that it makes invoke almost entirely unusable on Windows.

This workaround is not a great solution, by all accounts. If it detects that there are dead threads, but the process is not finished, it simply continues polling for another 3 seconds to wait for the process to complete gracefully. As I don't know the code that well, I'm willing to bet there's a better solution to this problem than just polling for an arbitrary amount of time. However, I've been using it all morning, in two different projects, and it seems to be working fine.
  • Loading branch information
Eric Borts committed Dec 30, 2019
1 parent 5122235 commit 1123485
Showing 1 changed file with 12 additions and 0 deletions.
12 changes: 12 additions & 0 deletions invoke/runners.py
Expand Up @@ -814,6 +814,18 @@ def wait(self):
proc_finished = self.process_is_finished
dead_threads = self.has_dead_threads
if proc_finished or dead_threads:
# WORKAROUND FOR RACE CONDITION (Windows, at least)
# https://github.com/pyinvoke/invoke/issues/683
#
# If there are dead threads, continue to wait for the process to finish since it
# might just be a race condition between thread (stdout, stderr) termination and
# subprocess (POpen) completion.
if dead_threads and not proc_finished:
t = 0.0
while t < 3.0 and not self.process_is_finished:
time.sleep(self.input_sleep)
t += self.input_sleep
# END WORKAROUND
break
time.sleep(self.input_sleep)

Expand Down

0 comments on commit 1123485

Please sign in to comment.