merge(chv-hybrid): 合入 B 轨——租约 + 排队 + 升级提示 + 网关门
合入 feat-chv-hybrid-b (667a427)。executor.py 两处内容冲突按 hunk
解决,全部取 B 侧;合入时发现 merge 复制出第二个 suspend_after_task
定义(A 版截断体),已删除。
集成统一(A/B 语义冲突三处,设计 §4.1 的 state 模型为准):
- state 模型:A 的 flag 模型(resident: True + legacy state)与 B
的 state 模型(state ∈ resident-active/paused/hibernated/demoted)
统一为 state 模型;_mark_resident_record 标记常驻时同时置
resident-active,_ensure_resident_capacity 同时认 flag 与 state。
- 容量等待:A 的 bool 版 _wait_for_capacity 改名 _poll_capacity,
B 的 raise 版保留原名;_wait_for_resident_slot 豁免已有常驻登记
的租户(它已占一个槽位,再等等于把自己的槽位算成满——A 轨
test_resident_cap_blocks_new_resident 第二腿在合入时因此失败,
已修并通过)。
- 档位大小写:A 用小写 paid/heavy,B 用 Paid/Heavy;比较一律走
_norm_tier + HYBRID_RESIDENT_TIERS(resident_tier_eligible 与
promote_to_resident 两处),fail-closed 语义不变。
- 严格快照校验翻为默认开启(设计 §2.2):_snapshot_strict_tenant
默认 True,显式 CHV_SNAPSHOT_STRICT_TENANT=0 才关闭;旧恢复
测试的 fixture 已登记带匹配 tenant 的快照,A 轨 legacy 测试改
为显式 opt-out 覆盖。
生产接线:worker 只调 dispatch_task,dispatch_task_hybrid 在生产
路径上无调用方;dispatch_task 顶部加一道门,warm_pool_size>=1 时
走 dispatch_task_hybrid,==0 时保持旧冷启语义(不成环:hybrid 的
<=0 分支退化为 dispatch_task_persistent,后者 <=0 调回 dispatch_task)。
旧网关测试更新(B 的语义变更):test_worker_gateway_guard_allows_chv
前加常驻登记;新增 test_worker_gateway_guard_denies_pool_vm。
测试:test_chv_hybrid_a/b 64 项 + 受影响旧测试 16 项(Gateway、
RestoreNoFallback、RestoreSnapshotTest)全部通过;全量待跑。
This commit is contained in:
commit
99d9e5771b
5 files changed
+1659
-120
No files matched your search
@@ -283,7 +283,7 @@ class HybridRouteTest(HybridACase):
|
||||
self.assertEqual(out["allocation"], "resident-cold")
|
||||
self.assertEqual(out["vm"], "chv-persist-paid1")
|
||||
rec = read_persistent_vm(self.state_dir, "paid1")
|
||||
self.assertEqual(rec["state"], "paused")
|
||||
self.assertEqual(rec["state"], "resident-active")
|
||||
self.assertEqual(rec["tier"], "paid")
|
||||
self.assertTrue(rec["resident"])
|
||||
self.assertEqual(ex._resident_count(), 1)
|
||||
@@ -301,7 +301,7 @@ class HybridRouteTest(HybridACase):
|
||||
self.assertEqual(out["vm"], "chv-persist-paid1")
|
||||
self.assertIn("resume_seconds", out)
|
||||
rec = read_persistent_vm(self.state_dir, "paid1")
|
||||
self.assertEqual(rec["state"], "paused")
|
||||
self.assertEqual(rec["state"], "resident-active")
|
||||
self.assertEqual(rec["tier"], "paid")
|
||||
self.assertTrue(rec["resident"])
|
||||
|
||||
@@ -311,7 +311,7 @@ class HybridRouteTest(HybridACase):
|
||||
for tenant in ("r1", "r2"):
|
||||
write_persistent_vm(self.state_dir, tenant, {
|
||||
"vm": "chv-persist-%s" % tenant,
|
||||
"tenant_id": tenant, "state": "paused",
|
||||
"tenant_id": tenant, "state": "resident-active",
|
||||
"origin": "task", "gitea_synced": False,
|
||||
"tier": "paid", "resident": True})
|
||||
self.assertEqual(ex._resident_count(), 2)
|
||||
@@ -324,11 +324,11 @@ class HybridRouteTest(HybridACase):
|
||||
ex2 = self.make_exec(env_extra={"CHV_QUEUE_TIMEOUT": "0"})
|
||||
write_persistent_vm(self.state_dir, "r1", {
|
||||
"vm": "chv-persist-r1", "tenant_id": "r1",
|
||||
"state": "paused", "origin": "task",
|
||||
"state": "resident-active", "origin": "task",
|
||||
"gitea_synced": False, "tier": "paid", "resident": True})
|
||||
write_persistent_vm(self.state_dir, "r2", {
|
||||
"vm": "chv-persist-r2", "tenant_id": "r2",
|
||||
"state": "paused", "origin": "task",
|
||||
"state": "resident-active", "origin": "task",
|
||||
"gitea_synced": False, "tier": "paid", "resident": True})
|
||||
self._socket("chv-persist-r1")
|
||||
self.vm_states["chv-persist-r1"] = "Paused"
|
||||
@@ -670,12 +670,15 @@ class SnapshotTenantStrictTest(HybridACase):
|
||||
"snapshot_tenant_mismatch")
|
||||
self.assertIn("vm_restore_denied", self._event_names())
|
||||
|
||||
def test_legacy_warn_pass_preserved_when_not_strict(self):
|
||||
# 混合模式未启用时,_validate_restore 沿用阶段 1 的
|
||||
# legacy 警告放行(旧测试依赖该语义,本轨不改)。
|
||||
def test_legacy_warn_pass_when_strict_opted_out(self):
|
||||
# 严格校验默认开启(设计 §2.2,集成时翻为默认);
|
||||
# legacy 警告放行只在显式 CHV_SNAPSHOT_STRICT_TENANT=0
|
||||
# 时保留(有未标记旧快照的环境的逃生口)。
|
||||
url = self._snap_url("chv-a")
|
||||
self._record("chv-a", url, None)
|
||||
ex = self.make_exec(env_extra={"CHV_WARM_POOL_SIZE": "0"})
|
||||
ex = self.make_exec(env_extra={
|
||||
"CHV_WARM_POOL_SIZE": "0",
|
||||
"CHV_SNAPSHOT_STRICT_TENANT": "0"})
|
||||
snapshot_url, _net = ex._validate_restore(
|
||||
{"id": "task-a", "project_id": "tenant-a"}, url)
|
||||
self.assertEqual(snapshot_url, url)
|
||||
@@ -684,5 +687,32 @@ class SnapshotTenantStrictTest(HybridACase):
|
||||
self.assertNotIn("vm_restore_denied", self._event_names())
|
||||
|
||||
|
||||
# -- dispatch 入口接线(集成时补)--------------------------------------
|
||||
class DispatchWiringTest(HybridACase):
|
||||
def test_dispatch_task_routes_to_hybrid_when_pool_on(self):
|
||||
# warm_pool_size>=1 时 dispatch_task 走混合路由。
|
||||
ex = self.make_exec()
|
||||
out = ex.dispatch_task(self._task(task_id="t1"))
|
||||
self.assertEqual(out["status"], "completed")
|
||||
self.assertEqual(out["route"], "pool")
|
||||
self.assertEqual(out["allocation"], "pool-cold")
|
||||
|
||||
def test_dispatch_task_routes_resident_when_paid(self):
|
||||
ex = self.make_exec()
|
||||
out = ex.dispatch_task(
|
||||
self._task(task_id="t1", project="paid1", tier="paid"))
|
||||
self.assertEqual(out["status"], "completed")
|
||||
self.assertEqual(out["route"], "resident")
|
||||
self.assertEqual(out["allocation"], "resident-cold")
|
||||
|
||||
def test_dispatch_task_stays_cold_when_pool_off(self):
|
||||
# warm_pool_size==0 时 dispatch_task 保持旧冷启语义,
|
||||
# 不进混合路由(结果无 route 字段)。
|
||||
ex = self.make_exec(env_extra={"CHV_WARM_POOL_SIZE": "0"})
|
||||
out = ex.dispatch_task(self._task(task_id="t1"))
|
||||
self.assertEqual(out["status"], "completed")
|
||||
self.assertNotIn("route", out)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user