0.1.12: retire a consumer the mesh stops asking for, after five stable passes, and wait for a person over the bound
The hourly release let a mistaken bulk unassignment drain one consumer an hour with nobody deciding. Per novox/hq ADR 0230 a consumer is retired (disabled, marked, data kept) only after the same unasked set in five consecutive passes; more than 3, or more than half of those held, waits for approve or reject. Deletion is a separate act of a person, of a retired consumer only.
This commit is contained in:
+7
-55
@@ -185,7 +185,7 @@ test("provisioner removes nothing while its contributions file cannot be used (n
|
||||
removed.push(p.as);
|
||||
},
|
||||
},
|
||||
{ receives, everyMs: 20, releaseEveryMs: 300 },
|
||||
{ receives, everyMs: 20 },
|
||||
);
|
||||
await waitFor(() => created.length === 2, 2000);
|
||||
|
||||
@@ -203,65 +203,17 @@ test("provisioner removes nothing while its contributions file cannot be used (n
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
}
|
||||
|
||||
// The file read and saying so still withdraws — within the brake (to-be 45 Phase 2): two at once is
|
||||
// over its bound, so nothing goes at first, then one at a time as the brake lets them go.
|
||||
// The file read and saying so is a result — but two of two held is over the bound (ADR 0230):
|
||||
// nothing is retired without a person, and approving that exact set retires both.
|
||||
await writeFile(receives, doc([]));
|
||||
await new Promise((r) => setTimeout(r, 150));
|
||||
assert.deepEqual(removed, [], "two consumers were withdrawn at once");
|
||||
await waitFor(() => removed.length === 2, 3000);
|
||||
for (let i = 0; i < 200 && (await stop.retirement()).waiting === null; i++) await new Promise((r) => setTimeout(r, 10));
|
||||
assert.notEqual((await stop.retirement()).waiting, null, "the retirement never waited for a person");
|
||||
assert.deepEqual(removed, [], "two of two consumers were retired without a person");
|
||||
await stop.approve(["mesh_anchor_mail", "mesh_anchor_forge"], { why: "both unassigned on purpose", by: "test" });
|
||||
assert.deepEqual([...removed].sort(), ["mesh_anchor_forge", "mesh_anchor_mail"]);
|
||||
stop();
|
||||
});
|
||||
|
||||
test("provisioner brakes a withdrawal of more than one consumer, and keeps one asked for again (to-be 45 Phase 2)", async () => {
|
||||
const dir = await mkdtemp(join(tmpdir(), "prov-"));
|
||||
const created: string[] = [];
|
||||
const removed: string[] = [];
|
||||
const receives = join(dir, "postgres-database.json");
|
||||
const doc = (given: unknown[]): string =>
|
||||
JSON.stringify({ contributions: 1, requirement: "postgres-database", given });
|
||||
const seven: unknown[] = [];
|
||||
for (let i = 1; i <= 7; i++) {
|
||||
await writeFile(join(dir, `c${i}.secret`), `pw-${i}\n`);
|
||||
seven.push({ from: `c${i}`, node: "anchor", as: `consumer${i}`, secret: join(dir, `c${i}.secret`) });
|
||||
}
|
||||
await writeFile(receives, doc(seven));
|
||||
const said: string[] = [];
|
||||
const was = console.error;
|
||||
console.error = (...args: unknown[]) => said.push(args.join(" "));
|
||||
const stop = runProvisioner(
|
||||
"postgres-database",
|
||||
{
|
||||
async create(p) {
|
||||
created.push(p.as);
|
||||
},
|
||||
async remove(p) {
|
||||
removed.push(p.as);
|
||||
},
|
||||
},
|
||||
{ receives, everyMs: 10, releaseEveryMs: 60_000 },
|
||||
);
|
||||
try {
|
||||
await waitFor(() => created.length === 7, 2000);
|
||||
// A file read whole that names nobody — the shape of 241 its first fix does not catch.
|
||||
await writeFile(receives, doc([]));
|
||||
await new Promise((r) => setTimeout(r, 200));
|
||||
assert.deepEqual(removed, [], "a withdrawal of seven at once was not braked");
|
||||
assert.ok(said.some((l) => l.includes("WITHDRAWAL BRAKED")), "the brake was not said");
|
||||
// The file is right again: nothing was withdrawn, and nothing will be.
|
||||
await writeFile(receives, doc(seven));
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
assert.deepEqual(removed, []);
|
||||
// One of seven goes as asked: within the bound.
|
||||
await writeFile(receives, doc(seven.slice(1)));
|
||||
await waitFor(() => removed.length === 1, 2000);
|
||||
assert.deepEqual(removed, ["consumer1"]);
|
||||
} finally {
|
||||
stop();
|
||||
console.error = was;
|
||||
}
|
||||
});
|
||||
|
||||
test("provisioner applies again what the backend no longer holds, and trusts memory without holds", async () => {
|
||||
const dir = await mkdtemp(join(tmpdir(), "prov-holds-"));
|
||||
await writeFile(join(dir, "webapp.secret"), "minted-pw\n");
|
||||
|
||||
Reference in New Issue
Block a user