|
@@ -988,7 +988,13 @@ def start_app():
|
|
|
"-ex", "run", "-ex", "bt", "--args", APP, str(APP_PORT)]
|
|
"-ex", "run", "-ex", "bt", "--args", APP, str(APP_PORT)]
|
|
|
process = subprocess.Popen(command, cwd=WORK, env=env,
|
|
process = subprocess.Popen(command, cwd=WORK, env=env,
|
|
|
stdout=log, stderr=subprocess.STDOUT)
|
|
stdout=log, stderr=subprocess.STDOUT)
|
|
|
- outcome = wait_for(lambda: (app_ready() and "ready")
|
|
|
|
|
|
|
+ # The ready probe must require OUR process alive: a free_port()
|
|
|
|
|
+ # TOCTOU can hand this port to another shard's app — ours then dies
|
|
|
|
|
+ # at bind (MHD error()) while the probe happily answers from the
|
|
|
|
|
+ # intruder (same admin seed), and every check would silently drive
|
|
|
|
|
+ # the WRONG app. poll() != None with a serving port is exactly that
|
|
|
|
|
+ # shape: take the exit branch, the start_bundle retry re-ports.
|
|
|
|
|
+ outcome = wait_for(lambda: (app_ready() and process.poll() is None and "ready")
|
|
|
or (process.poll() is not None and "app-exited-%d" % process.poll())
|
|
or (process.poll() is not None and "app-exited-%d" % process.poll())
|
|
|
or False, timeout=30, what="app ready")
|
|
or False, timeout=30, what="app ready")
|
|
|
if outcome is None:
|
|
if outcome is None:
|
|
@@ -2147,16 +2153,22 @@ def bundle_dispatch(ctx):
|
|
|
act(auth, ref_project["attach_rule"], {"rule_id": str(rule_id("Reference rule"))})
|
|
act(auth, ref_project["attach_rule"], {"rule_id": str(rule_id("Reference rule"))})
|
|
|
|
|
|
|
|
tasks_state = slot_public(auth, "/tasks", "tasks")
|
|
tasks_state = slot_public(auth, "/tasks", "tasks")
|
|
|
- task_id_tmp = create_queued(auth, {
|
|
|
|
|
|
|
+ # Draft-first (deterministic rule attachment): the dispatcher claims
|
|
|
|
|
+ # a queued task on its 1s tick, which under load could beat the
|
|
|
|
|
+ # attach_rule calls below and ship an assignment without the task's
|
|
|
|
|
+ # own rules — attach while draft, enqueue last.
|
|
|
|
|
+ act(auth, tasks_state["create"], {
|
|
|
"project_id": "1",
|
|
"project_id": "1",
|
|
|
"title": "Rules dispatch",
|
|
"title": "Rules dispatch",
|
|
|
"description": "Effective rule set rides the /start payload.",
|
|
"description": "Effective rule set rides the /start payload.",
|
|
|
"priority": "2",
|
|
"priority": "2",
|
|
|
})
|
|
})
|
|
|
- rule_task = task_id_tmp
|
|
|
|
|
|
|
+ rule_task = int([t["id"] for t in slot_public(auth, "/tasks", "tasks")["tasks"]
|
|
|
|
|
+ if t["title"] == "Rules dispatch"][0])
|
|
|
detail = task_state(auth, rule_task)
|
|
detail = task_state(auth, rule_task)
|
|
|
act(auth, detail["attach_rule"], {"rule_id": str(rule_id("Write Vala docs"))})
|
|
act(auth, detail["attach_rule"], {"rule_id": str(rule_id("Write Vala docs"))})
|
|
|
act(auth, detail["attach_rule"], {"rule_id": str(rule_id("Use Invercargill"))})
|
|
act(auth, detail["attach_rule"], {"rule_id": str(rule_id("Use Invercargill"))})
|
|
|
|
|
+ enqueue_task(auth, rule_task)
|
|
|
detail = task_state(auth, rule_task)
|
|
detail = task_state(auth, rule_task)
|
|
|
check(sorted(r["name"] for r in detail["rules"]) == ["Use Invercargill", "Write Vala docs"],
|
|
check(sorted(r["name"] for r in detail["rules"]) == ["Use Invercargill", "Write Vala docs"],
|
|
|
"task page lists its attached rules")
|
|
"task page lists its attached rules")
|