metis-desk/apps/server/src/resource-scope-concurrency.fixture.ts
2026-10-25 01:19:17 +02:00

62 lines
1.7 KiB
TypeScript

import assert from "node:assert/strict";
import { execFile } from "node:child_process";
import { promisify } from "node:util";
const execute = promisify(execFile);
export function latch() {
let release: () => void = () => {
throw new Error("Barrera sin inicializar.");
};
const promise = new Promise<void>((resolve) => {
release = resolve;
});
return { promise, release };
}
export async function waitBarrier(promise: Promise<void>) {
let timer: NodeJS.Timeout | undefined;
try {
await Promise.race([
promise,
new Promise<never>((_resolve, reject) => {
timer = setTimeout(
() => reject(new Error("No se alcanzó la barrera transaccional.")),
15000
);
}),
]);
} finally {
clearTimeout(timer);
}
}
/** Observa una espera real de InnoDB fuera del pool probado; no vuelca credenciales del contenedor. */
export async function waitCatalogLock(container: string) {
assert.match(container, /^metis-scope-test-[a-f0-9]+$/u);
const deadline = Date.now() + 10000;
while (Date.now() < deadline) {
const { stdout } = await execute(
"docker",
[
"exec",
container,
"sh",
"-c",
'MYSQL_PWD="$MARIADB_ROOT_PASSWORD" mariadb -uroot -N -B --execute="SELECT COUNT(*) FROM information_schema.INNODB_LOCK_WAITS w JOIN information_schema.INNODB_LOCKS b ON b.lock_id=w.blocking_lock_id WHERE b.lock_table LIKE \'%resource_catalogs%\'"',
],
{ timeout: 5000 }
);
if (Number(stdout.trim()) > 0) {
return;
}
await new Promise<void>((resolve) => setImmediate(resolve));
}
throw new Error("No se observó la espera de InnoDB esperada.");
}