Inline memory measurement script to fix base ref compatibility

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2025-12-03 04:05:29 +00:00
parent 0e42064039
commit 6f76a121ef
2 changed files with 64 additions and 154 deletions

View File

@ -62,8 +62,70 @@ jobs:
run: pnpm --filter backend migrate
- name: Measure memory usage
run: |
# Start the server and measure memory usage
node packages/backend/scripts/measure-memory.mjs > ${{ matrix.memory-json-name }}
# Inline script to start the server and measure memory usage
# This is inlined to work with both base and head refs
node --input-type=module -e '
import { fork } from "node:child_process";
import { setTimeout } from "node:timers/promises";
import { readFile } from "node:fs/promises";
import { execSync } from "node:child_process";
const STARTUP_TIMEOUT = 120000;
const MEMORY_SETTLE_TIME = 10000;
async function measureMemory() {
const serverProcess = fork("./packages/backend/built/boot/entry.js", [], {
cwd: process.cwd(),
env: { ...process.env, NODE_ENV: "test" },
stdio: ["pipe", "pipe", "pipe", "ipc"],
});
let serverReady = false;
serverProcess.on("message", (msg) => { if (msg === "ok") serverReady = true; });
serverProcess.stdout?.on("data", (d) => process.stderr.write("[server] " + d));
serverProcess.stderr?.on("data", (d) => process.stderr.write("[server] " + d));
serverProcess.on("error", (e) => process.stderr.write("[error] " + e + "\n"));
const start = Date.now();
while (!serverReady) {
if (Date.now() - start > STARTUP_TIMEOUT) {
serverProcess.kill("SIGTERM");
throw new Error("Server startup timeout");
}
await setTimeout(100);
}
const startupTime = Date.now() - start;
process.stderr.write("Server started in " + startupTime + "ms\n");
await setTimeout(MEMORY_SETTLE_TIME);
const pid = serverProcess.pid;
let memoryInfo;
try {
const status = await readFile("/proc/" + pid + "/status", "utf-8");
const rss = status.match(/VmRSS:\s+(\d+)\s+kB/);
memoryInfo = { rss: rss ? parseInt(rss[1], 10) * 1024 : null };
} catch {
try {
const ps = execSync("ps -o rss= -p " + pid, { encoding: "utf-8" });
memoryInfo = { rss: parseInt(ps.trim(), 10) * 1024 };
} catch {
memoryInfo = { rss: null, error: "Could not measure memory" };
}
}
serverProcess.kill("SIGTERM");
let exited = false;
await new Promise((resolve) => {
serverProcess.on("exit", () => { exited = true; resolve(); });
setTimeout(10000).then(() => { if (!exited) serverProcess.kill("SIGKILL"); resolve(); });
});
console.log(JSON.stringify({ timestamp: new Date().toISOString(), startupTimeMs: startupTime, memory: memoryInfo }, null, 2));
}
measureMemory().catch((e) => { console.error(JSON.stringify({ error: e.message })); process.exit(1); });
' > ${{ matrix.memory-json-name }}
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:

View File

@ -1,152 +0,0 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
/**
* This script starts the Misskey backend server, waits for it to be ready,
* measures memory usage, and outputs the result as JSON.
*
* Usage: node scripts/measure-memory.mjs
*/
import { fork } from 'node:child_process';
import { setTimeout } from 'node:timers/promises';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const STARTUP_TIMEOUT = 120000; // 120 seconds timeout for server startup
const MEMORY_SETTLE_TIME = 10000; // Wait 10 seconds after startup for memory to settle
async function measureMemory() {
const startTime = Date.now();
// Start the Misskey backend server using fork to enable IPC
const serverProcess = fork(join(__dirname, '../built/boot/entry.js'), [], {
cwd: join(__dirname, '..'),
env: {
...process.env,
NODE_ENV: 'test',
},
stdio: ['pipe', 'pipe', 'pipe', 'ipc'],
});
let serverReady = false;
// Listen for the 'ok' message from the server indicating it's ready
serverProcess.on('message', (message) => {
if (message === 'ok') {
serverReady = true;
}
});
// Handle server output
serverProcess.stdout?.on('data', (data) => {
process.stderr.write(`[server stdout] ${data}`);
});
serverProcess.stderr?.on('data', (data) => {
process.stderr.write(`[server stderr] ${data}`);
});
// Handle server error
serverProcess.on('error', (err) => {
process.stderr.write(`[server error] ${err}\n`);
});
// Wait for server to be ready or timeout
const startupStartTime = Date.now();
while (!serverReady) {
if (Date.now() - startupStartTime > STARTUP_TIMEOUT) {
serverProcess.kill('SIGTERM');
throw new Error('Server startup timeout');
}
await setTimeout(100);
}
const startupTime = Date.now() - startupStartTime;
process.stderr.write(`Server started in ${startupTime}ms\n`);
// Wait for memory to settle
await setTimeout(MEMORY_SETTLE_TIME);
// Get memory usage from the server process via /proc
const pid = serverProcess.pid;
let memoryInfo;
try {
const fs = await import('node:fs/promises');
// Read /proc/[pid]/status for detailed memory info
const status = await fs.readFile(`/proc/${pid}/status`, 'utf-8');
const vmRssMatch = status.match(/VmRSS:\s+(\d+)\s+kB/);
const vmDataMatch = status.match(/VmData:\s+(\d+)\s+kB/);
const vmSizeMatch = status.match(/VmSize:\s+(\d+)\s+kB/);
memoryInfo = {
rss: vmRssMatch ? parseInt(vmRssMatch[1], 10) * 1024 : null,
heapUsed: vmDataMatch ? parseInt(vmDataMatch[1], 10) * 1024 : null,
vmSize: vmSizeMatch ? parseInt(vmSizeMatch[1], 10) * 1024 : null,
};
} catch (err) {
// Fallback: use ps command
process.stderr.write(`Warning: Could not read /proc/${pid}/status: ${err}\n`);
const { execSync } = await import('node:child_process');
try {
const ps = execSync(`ps -o rss= -p ${pid}`, { encoding: 'utf-8' });
const rssKb = parseInt(ps.trim(), 10);
memoryInfo = {
rss: rssKb * 1024,
heapUsed: null,
vmSize: null,
};
} catch {
memoryInfo = {
rss: null,
heapUsed: null,
vmSize: null,
error: 'Could not measure memory',
};
}
}
// Stop the server
serverProcess.kill('SIGTERM');
// Wait for process to exit
let exited = false;
await new Promise((resolve) => {
serverProcess.on('exit', () => {
exited = true;
resolve(undefined);
});
// Force kill after 10 seconds if not exited
setTimeout(10000).then(() => {
if (!exited) {
serverProcess.kill('SIGKILL');
}
resolve(undefined);
});
});
const result = {
timestamp: new Date().toISOString(),
startupTimeMs: startupTime,
memory: memoryInfo,
};
// Output as JSON to stdout
console.log(JSON.stringify(result, null, 2));
}
measureMemory().catch((err) => {
console.error(JSON.stringify({
error: err.message,
timestamp: new Date().toISOString(),
}));
process.exit(1);
});