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((resolve) => { release = resolve; }); return { promise, release }; } export async function waitBarrier(promise: Promise) { let timer: NodeJS.Timeout | undefined; try { await Promise.race([ promise, new Promise((_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((resolve) => setImmediate(resolve)); } throw new Error("No se observó la espera de InnoDB esperada."); }