问题描述
当前,我可以使用带有@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