Buildbot:工人空闲
Buildbot: worker is idle
我注意到构建在工人之间的分布不是最优的,80% 的时间构建是 运行 忙碌的工人。
如果你看一下图像,tmp_worker1
可以处理triggered_build_1
,但它是空闲的!由于某种原因,triggered_build_1
处于获取锁定状态并分配给忙碌的 example-worker
我有下一个设置:
- 3 名工人
- 1 位主要建设者
- 3 个可触发的构建器(带锁)
主要源代码如下
# triggerable scheduler
c['schedulers'].append(schedulers.Triggerable(name="trigger_from_main",
builderNames=['triggered_build_0', 'triggered_build_1', 'triggered_build_2']))
# main builder factory
factory_main = util.BuildFactory()
# trigger
factory_main.addStep(steps.Trigger(
schedulerNames=['trigger_from_main'],
waitForFinish=True,
haltOnFailure=True,
name='trigger'
))
# main builder
c['builders'].append(
util.BuilderConfig(name="test_main",
workernames=['example-worker', 'tmp_worker0', 'tmp_worker1'],
factory=factory_main,
)
)
# lock
worker_lock = [util.WorkerLock("worker_builds", maxCount=1).access('counting')]
# 1st of 3 sub-builder
c['builders'].append(
util.BuilderConfig(name="triggered_build_0",
workernames=['example-worker', 'tmp_worker0', 'tmp_worker1'],
factory=factory_subbuild,
locks=worker_lock,
)
)
# 2nd of 3 sub-builder
...
# 3rd of 3 sub-builder
...
此行为是由于锁和主节点分发构建的方式而触发的。
当构建需要 运行 时,大师执行以下步骤 (link to the source code):
- Select随机一个工人
- 检查工人和构建是否匹配
- 检查构建是否可以获取 worker 所需的锁
- 将构建分配给主人
并且当在 worker 上开始构建时,它会获取锁。
因此如果 master 在获取锁之前检查下一个构建的调度要求,它可以在同一个 worker 上调度一个新的构建(即使他们需要相同的锁)。
如果您将分配构建的工作人员隔离以便为工作人员提供足够的时间来获取锁,则可以解决此问题。
您可以使用 canStartBuild
函数执行此操作,该函数是 运行 就在将构建分配给 worker (docs) 之前。
def canStartBuildLockQuarantine(builder, wfb, request):
# Put the worker in quarantine for 5 seconds
wfb.worker.quarantine_timeout = 5
wfb.worker.putInQuarantine()
# Reset wfb.worker.quarantine_timeout
wfb.worker.resetQuarantine()
return True
并将其交给将要锁的工人。
c['builders'].append(
util.BuilderConfig(name="triggered_build_0",
workernames=['example-worker', 'tmp_worker0', 'tmp_worker1'],
factory=factory_subbuild,
canStartBuild=canStartBuildLockQuarantine,
locks=worker_lock,
)
)
我注意到构建在工人之间的分布不是最优的,80% 的时间构建是 运行 忙碌的工人。
如果你看一下图像,tmp_worker1
可以处理triggered_build_1
,但它是空闲的!由于某种原因,triggered_build_1
处于获取锁定状态并分配给忙碌的 example-worker
我有下一个设置:
- 3 名工人
- 1 位主要建设者
- 3 个可触发的构建器(带锁)
主要源代码如下
# triggerable scheduler
c['schedulers'].append(schedulers.Triggerable(name="trigger_from_main",
builderNames=['triggered_build_0', 'triggered_build_1', 'triggered_build_2']))
# main builder factory
factory_main = util.BuildFactory()
# trigger
factory_main.addStep(steps.Trigger(
schedulerNames=['trigger_from_main'],
waitForFinish=True,
haltOnFailure=True,
name='trigger'
))
# main builder
c['builders'].append(
util.BuilderConfig(name="test_main",
workernames=['example-worker', 'tmp_worker0', 'tmp_worker1'],
factory=factory_main,
)
)
# lock
worker_lock = [util.WorkerLock("worker_builds", maxCount=1).access('counting')]
# 1st of 3 sub-builder
c['builders'].append(
util.BuilderConfig(name="triggered_build_0",
workernames=['example-worker', 'tmp_worker0', 'tmp_worker1'],
factory=factory_subbuild,
locks=worker_lock,
)
)
# 2nd of 3 sub-builder
...
# 3rd of 3 sub-builder
...
此行为是由于锁和主节点分发构建的方式而触发的。
当构建需要 运行 时,大师执行以下步骤 (link to the source code):
- Select随机一个工人
- 检查工人和构建是否匹配
- 检查构建是否可以获取 worker 所需的锁
- 将构建分配给主人
并且当在 worker 上开始构建时,它会获取锁。
因此如果 master 在获取锁之前检查下一个构建的调度要求,它可以在同一个 worker 上调度一个新的构建(即使他们需要相同的锁)。
如果您将分配构建的工作人员隔离以便为工作人员提供足够的时间来获取锁,则可以解决此问题。
您可以使用 canStartBuild
函数执行此操作,该函数是 运行 就在将构建分配给 worker (docs) 之前。
def canStartBuildLockQuarantine(builder, wfb, request):
# Put the worker in quarantine for 5 seconds
wfb.worker.quarantine_timeout = 5
wfb.worker.putInQuarantine()
# Reset wfb.worker.quarantine_timeout
wfb.worker.resetQuarantine()
return True
并将其交给将要锁的工人。
c['builders'].append(
util.BuilderConfig(name="triggered_build_0",
workernames=['example-worker', 'tmp_worker0', 'tmp_worker1'],
factory=factory_subbuild,
canStartBuild=canStartBuildLockQuarantine,
locks=worker_lock,
)
)