Search code examples
pythonpython-3.xpython-multiprocessingpython-multithreading

How to end all tasks in a ThreadPoolExecutor if one of them can throw an exception


I have one task that I want to do:

def task(body):
    # some logic that which can throw an exception
    # if something goes wrong
    do_task(body) 

and the logic inside this task can throw an exception

And I have execute method with executor:

def execute():
    executor = ThreadPoolExecutor(max_workers=4)
    future1 = executor.submit(task, body1)
    future2 = executor.submit(task, body2)
    future3 = executor.submit(task, body3)
    future4 = executor.submit(task, body4)
    
    result1 = future1.result()
    result2 = future2.result()
    result3 = future3.result()
    result4 = future4.result()

And I want if at least one task crashes - do not wait for the completion of other tasks and stopped everything. How can I do this correctly?


Solution

  • To abandon waiting for other tasks when one raises, you can use concurrent.futures.wait() with the FIRST_EXCEPTION flag:

    def execute():
        executor = ThreadPoolExecutor(max_workers=4)
        future1 = executor.submit(task, body1)
        future2 = executor.submit(task, body2)
        future3 = executor.submit(task, body3)
        future4 = executor.submit(task, body4)
    
        done, not_done = concurrent.futures.wait(
            [future1, future2, future3, future4],
            return_when=concurrent.futures.FIRST_EXCEPTION
        )
        if not_done:
            # at least one future has raised - you can return here
            # or propagate the exception
            #list(not_done)[0].result()  # re-raises exception here
            return  # ignores exception and returns
    
        result1 = future1.result()
        result2 = future2.result()
        result3 = future3.result()
        result4 = future4.result()
        ...
    

    Note that the remaining tasks will still keep running in the background. There is no way to stop them forcibly.