如果其中一个任务失败,如何中止在多个主机上并行运行的一组架构任务?

问题描述

当前,我可以使用带有@runs_once的顶级任务快速执行部署到多个主机,该任务执行以@parallel装饰的任务,该任务将拾取角色中定义的所有主机。

我可以运行部署任务:

fab -R production deploy:myApp.tgz

当前,如果其中一项任务失败,则会发生以下情况:

[host2] Executing task 'deploy'
[host1] Executing task '_deploy'
[host2] deploy Failed on host 2
[host3] Executing task '_deploy'
[host1] deployed b69488da3e on host 1 
[host3] deployed b69488da3e on host 3 
Fatal error: deploy Failed on host 2

Aborting.

如您所见,在完成所有并行任务之前,结构会话不会中止。如果我要在生产环境中运行此主机,即使第一个主机出现故障,它也可以轻松关闭所有主机。

理想情况下,一旦任务失败,我想中止会话。但是this is not possible。我已经尝试了结构函数abort('Failed task')local("exit 1")以及更传统的sys.exit(1)os._exit(1)。我能够停止正在运行的并行任务的结构会话的唯一方法键盘中断。

因此,我想首先在单个主机上运行,​​然后在失败的情况下中止运行,而不是继续部署到所有主机。这将使我能够获得并行执行相对于串行执行的大部分速度优势(检查应用程序是否备份涉及大量等待),同时防止灾难性破坏所有生产型主机的灾难情况。有点像“金丝雀”模式。通过将列表传递给execute()或使用设置上下文,我无法在运行时修改主机列表。

使用: Python 2 面料1.14.1 帕拉米科2.6.0

解决方法

您可以通过以下方式实现这种金丝雀模式:

def _one_off_generator(fn,one_off=True):
    if one_off:
        @runs_once                                                                                                                      
        def once(*args):
            return fn(*args)
        return once
    else:
        @parallel                                                                                                                       
        def many(*args):                                                                                                                
            return fn(*args)
        return many

@task
@runs_once
def deploy(fn):
    
    canary_deploy = _one_off_generator(_deploy)

    execute(canary_deploy,fn)

    parallel_deploy = _one_off_generator(_deploy,one_off=False)
    prev = execute(parallel_deploy,fn)
@task
def _deploy(fn):
    #deploy things