From 6f76a121efd450c257167cce6e298c59936f4e37 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 3 Dec 2025 04:05:29 +0000 Subject: [PATCH] Inline memory measurement script to fix base ref compatibility Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com> --- .github/workflows/get-backend-memory.yml | 66 ++++++++- packages/backend/scripts/measure-memory.mjs | 152 -------------------- 2 files changed, 64 insertions(+), 154 deletions(-) delete mode 100644 packages/backend/scripts/measure-memory.mjs diff --git a/.github/workflows/get-backend-memory.yml b/.github/workflows/get-backend-memory.yml index 6f36c088f1..8c40ded073 100644 --- a/.github/workflows/get-backend-memory.yml +++ b/.github/workflows/get-backend-memory.yml @@ -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: diff --git a/packages/backend/scripts/measure-memory.mjs b/packages/backend/scripts/measure-memory.mjs deleted file mode 100644 index 017252d7ec..0000000000 --- a/packages/backend/scripts/measure-memory.mjs +++ /dev/null @@ -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); -});