Skip to content

Race condition in execute() #654

Description

@PaulMcMillan

I've encountered what I believe to be a race condition in execute() which results in a job queue that never terminates. This error occurs reliably when running fabric over a VPN (especially from far away from the target machines) but does not ever occur when running fabric on the same local network as the target machines.

I'm using the remote command timeout wrapper described in my comment on #249 with timeout = 30

Relevant settings:

socket.socket().timeout = 30.0
env.use_exceptions_for['network'] = True
env.warn_only=False
env.parallel = True

My code is of the form:

@task
def foo():
    sudo('do stuff')

@task
def run():
    try:
        execute(foo)
    except KeyboardInterrupt:
        print('some closing info')

When I run this against 4 machines with debug output enabled, I get something like this:

Popping '10.0.0.16' off the queue and starting it
Popping '10.0.0.1' off the queue and starting it
Popping '10.0.0.3' off the queue and starting it
Popping '10.0.0.9' off the queue and starting it
[10.0.0.16] <run output>
Job queue found finished proc: 10.0.0.16.
Job queue has 3 running.
[10.0.0.9] <run output>
[10.0.0.3] <run output>
Job queue found finished proc: 10.0.0.9.
Job queue has 2 running.
[10.0.0.1] <run output>

At this point, the code hangs indefinitely. When I hit CTRL-C, I get this:

^CKeyboardInterrupt()
<My finalizing printed output from the catch>

Done.
Disconnecting from 10.0.0.16... done.
Disconnecting from 10.0.0.1... done.
Disconnecting from 10.0.0.3... done.

Again, it hangs. So I hit CTRL-C again, and get this:

^CError in atexit._run_exitfuncs:
Traceback (most recent call last):
  File "/usr/lib/python2.7/atexit.py", line 24, in _run_exitfuncs
    func(*targs, **kargs)
  File "/usr/lib/python2.7/multiprocessing/util.py", line 295, in _exit_function
    p.join()
  File "/usr/lib/python2.7/multiprocessing/process.py", line 145, in join
    res = self._popen.wait(timeout)
  File "/usr/lib/python2.7/multiprocessing/forking.py", line 148, in wait
    return self.poll(0)
  File "/usr/lib/python2.7/multiprocessing/forking.py", line 133, in poll
    pid, sts = os.waitpid(self.pid, flag)
KeyboardInterrupt
Error in sys.exitfunc:
Traceback (most recent call last):
  File "/usr/lib/python2.7/atexit.py", line 24, in _run_exitfuncs
    func(*targs, **kargs)
  File "/usr/lib/python2.7/multiprocessing/util.py", line 295, in _exit_function
    p.join()
  File "/usr/lib/python2.7/multiprocessing/process.py", line 145, in join
    res = self._popen.wait(timeout)
  File "/usr/lib/python2.7/multiprocessing/forking.py", line 148, in wait
    return self.poll(0)
  File "/usr/lib/python2.7/multiprocessing/forking.py", line 133, in poll
    pid, sts = os.waitpid(self.pid, flag)
KeyboardInterrupt

After printing this traceback, it finally closes out.

My best guess is that something is causing the execute queue to not realize it is empty, or to not completely cleanup a job after it is finished.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions