docs(ops): record 103 goosed native migration and add migrate tooling
Memind CI / Test, build, and release guards (pull_request) Has been cancelled
Memind CI / Test, build, and release guards (pull_request) Has been cancelled
Document the completed Docker-to-native goosed pool cutover on 103, add the production migrate script with backup/rollback paths, and extend local native pool soak/metrics helpers used as migration gates. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env node
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { Agent, fetch as undiciFetch } from 'undici';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const root = path.join(__dirname, '..');
|
||||
const insecureDispatcher = new Agent({ connect: { rejectUnauthorized: false } });
|
||||
|
||||
function loadEnvFile(filePath) {
|
||||
if (!fs.existsSync(filePath)) return;
|
||||
for (const line of fs.readFileSync(filePath, 'utf8').split('\n')) {
|
||||
const trimmed = line.trim();
|
||||
if (!trimmed || trimmed.startsWith('#')) continue;
|
||||
const idx = trimmed.indexOf('=');
|
||||
if (idx < 0) continue;
|
||||
const key = trimmed.slice(0, idx).trim();
|
||||
const value = trimmed.slice(idx + 1).trim();
|
||||
if (!process.env[key]) process.env[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
loadEnvFile(path.join(root, '.env'));
|
||||
|
||||
const targets = (process.env.TKMIND_API_TARGETS || process.env.GOOSED_NATIVE_POOL_PORTS || '18006,18007')
|
||||
.split(/[,\s]+/)
|
||||
.map((value) => value.trim())
|
||||
.filter(Boolean)
|
||||
.flatMap((value) => (
|
||||
value.startsWith('http')
|
||||
? [value]
|
||||
: [`https://127.0.0.1:${value.replace(/^:/, '')}`]
|
||||
));
|
||||
|
||||
if (targets.length === 0) {
|
||||
console.error('No targets configured. Set TKMIND_API_TARGETS or GOOSED_NATIVE_POOL_PORTS.');
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
const results = [];
|
||||
for (const target of targets) {
|
||||
const started = Date.now();
|
||||
try {
|
||||
const res = await undiciFetch(`${target.replace(/\/$/, '')}/status`, {
|
||||
dispatcher: insecureDispatcher,
|
||||
});
|
||||
const body = (await res.text()).trim();
|
||||
results.push({
|
||||
target,
|
||||
ok: res.ok && body === 'ok',
|
||||
status: res.status,
|
||||
body,
|
||||
ms: Date.now() - started,
|
||||
});
|
||||
} catch (err) {
|
||||
results.push({
|
||||
target,
|
||||
ok: false,
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
ms: Date.now() - started,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
console.log(JSON.stringify({
|
||||
ok: results.every((item) => item.ok),
|
||||
count: results.length,
|
||||
results,
|
||||
}, null, 2));
|
||||
|
||||
process.exit(results.every((item) => item.ok) ? 0 : 1);
|
||||
Reference in New Issue
Block a user