use platform services in startup routines

This commit is contained in:
Hazelnoot 2025-10-22 23:36:40 -04:00
parent b751f9c96d
commit 86ca3921c9
14 changed files with 117 additions and 93 deletions

View file

@ -12,7 +12,7 @@ import { QueueStatsService } from '@/daemons/QueueStatsService.js';
import { ServerStatsService } from '@/daemons/ServerStatsService.js';
import { ServerService } from '@/server/ServerService.js';
import { MainModule } from '@/MainModule.js';
import { envOption } from '@/env.js';
import { EnvService } from '@/global/EnvService.js';
import { ApLogCleanupService } from '@/daemons/ApLogCleanupService.js';
export async function server() {
@ -27,7 +27,9 @@ export async function server() {
if (process.env.NODE_ENV !== 'test') {
app.get(ChartManagementService).start();
}
if (!envOption.noDaemons) {
const envService = app.get(EnvService);
if (!envService.options.noDaemons) {
app.get(QueueStatsService).start();
app.get(ServerStatsService).start();
app.get(ApLogCleanupService).start();

View file

@ -13,8 +13,10 @@ import { inspect } from 'node:util';
import chalk from 'chalk';
import Xev from 'xev';
import Logger from '@/logger.js';
import { EnvService } from '@/global/EnvService.js';
import { LoggerService } from '@/core/LoggerService.js';
import { NativeTimeService } from '@/global/TimeService.js';
import { prepEnv } from '@/boot/prepEnv.js';
import { envOption } from '../env.js';
import { masterMain } from './master.js';
import { workerMain } from './worker.js';
import { readyRef } from './ready.js';
@ -25,14 +27,20 @@ process.title = `Misskey (${cluster.isPrimary ? 'master' : 'worker'})`;
prepEnv();
const logger = new Logger('core', 'cyan');
const clusterLogger = logger.createSubLogger('cluster', 'orange');
const ev = new Xev();
// We wrap this in a main function, that gets called,
// because not all platforms support top level await :/
async function main() {
const envService = new EnvService();
const envOption = envService.options;
// eslint-disable-next-line no-restricted-globals
const loggerService = new LoggerService(console, new NativeTimeService(), envService);
const logger = loggerService.getLogger('core', 'cyan');
const clusterLogger = logger.createSubLogger('cluster', 'orange');
//#region Events
// Listen new workers
cluster.on('fork', worker => {
@ -97,18 +105,18 @@ async function main() {
if (!envOption.disableClustering) {
if (cluster.isPrimary) {
logger.info(`Start main process... pid: ${process.pid}`);
await masterMain();
await masterMain(loggerService, envService);
ev.mount();
} else if (cluster.isWorker) {
logger.info(`Start worker process... pid: ${process.pid}`);
await workerMain();
await workerMain(loggerService, envService);
} else {
throw new Error('Unknown process type');
}
} else {
// 非clusterの場合はMasterのみが起動するため、Workerの処理は行わない(cluster.isWorker === trueの状態でこのブロックに来ることはない)
logger.info(`Start main process... pid: ${process.pid}`);
await masterMain();
await masterMain(loggerService, envService);
ev.mount();
}

View file

@ -13,11 +13,14 @@ import chalk from 'chalk';
import chalkTemplate from 'chalk-template';
import * as Sentry from '@sentry/node';
import { nodeProfilingIntegration } from '@sentry/profiling-node';
import Logger from '@/logger.js';
import type Logger from '@/logger.js';
import { loadConfig } from '@/config.js';
import type { Config } from '@/config.js';
import type { LoggerService } from '@/core/LoggerService.js';
import type { EnvService } from '@/global/EnvService.js';
import type { EnvOption } from '@/env.js';
import { renderInlineError } from '@/misc/render-inline-error.js';
import { showMachineInfo } from '@/misc/show-machine-info.js';
import { envOption } from '@/env.js';
import { jobQueue, server } from './common.js';
const _filename = fileURLToPath(import.meta.url);
@ -25,12 +28,9 @@ const _dirname = dirname(_filename);
const meta = JSON.parse(fs.readFileSync(`${_dirname}/../../../../built/meta.json`, 'utf-8'));
const logger = new Logger('core', 'cyan');
const bootLogger = logger.createSubLogger('boot', 'magenta');
const themeColor = chalk.hex('#86b300');
function greet() {
function greet(logger: Logger, bootLogger: Logger, envOption: EnvOption) {
if (!envOption.quiet) {
//#region Misskey logo
logger.info(themeColor(' _____ _ _ '));
@ -57,20 +57,25 @@ function greet() {
/**
* Init master process
*/
export async function masterMain() {
export async function masterMain(loggerService: LoggerService, envService: EnvService) {
let config!: Config;
const logger = loggerService.getLogger('core', 'cyan');
const bootLogger = logger.createSubLogger('boot', 'magenta');
const envOption = envService.options;
// initialize app
try {
greet();
showEnvironment();
greet(logger, bootLogger, envOption);
showEnvironment(bootLogger);
await showMachineInfo(bootLogger);
showNodejsVersion();
config = loadConfigBoot();
showNodejsVersion(bootLogger);
config = loadConfig(loggerService);
//await connectDb();
if (config.pidFile) fs.writeFileSync(config.pidFile, process.pid.toString());
} catch (e) {
bootLogger.error('Fatal error occurred during initialization', null, true);
bootLogger.error(`Fatal error occurred during initialization: ${renderInlineError(e)}`, { e }, true);
process.exit(1);
}
@ -125,7 +130,7 @@ export async function masterMain() {
process.exit(1);
}
await spawnWorkers(config.clusterLimit);
await spawnWorkers(bootLogger, config.clusterLimit);
} else {
// clusterモジュール無効時
@ -147,7 +152,7 @@ export async function masterMain() {
}
}
function showEnvironment(): void {
function showEnvironment(bootLogger: Logger): void {
const env = process.env.NODE_ENV;
const logger = bootLogger.createSubLogger('env');
logger.info(typeof env === 'undefined' ? 'NODE_ENV is not set' : `NODE_ENV: ${env}`);
@ -158,34 +163,12 @@ function showEnvironment(): void {
}
}
function showNodejsVersion(): void {
function showNodejsVersion(bootLogger: Logger): void {
const nodejsLogger = bootLogger.createSubLogger('nodejs');
nodejsLogger.info(`Version ${process.version} detected.`);
}
function loadConfigBoot(): Config {
const configLogger = bootLogger.createSubLogger('config');
let config;
try {
config = loadConfig();
} catch (exception) {
if (typeof exception === 'string') {
configLogger.error('Exception loading config:', exception);
process.exit(1);
} else if ((exception as any).code === 'ENOENT') {
configLogger.error('Configuration file not found', null, true);
process.exit(1);
}
throw exception;
}
configLogger.info('Loaded');
return config;
}
/*
async function connectDb(): Promise<void> {
const dbLogger = bootLogger.createSubLogger('db');
@ -204,17 +187,17 @@ async function connectDb(): Promise<void> {
}
*/
async function spawnWorkers(limit = 1) {
async function spawnWorkers(bootLogger: Logger, limit = 1) {
const cpuCount = os.cpus().length;
// in some weird environments, node can't count the CPUs; we trust the config in those cases
const workers = cpuCount === 0 ? limit : Math.min(limit, cpuCount);
bootLogger.info(`Starting ${workers} worker${workers === 1 ? '' : 's'}...`);
await Promise.all([...Array(workers)].map(spawnWorker));
await Promise.all([...Array(workers)].map(() => spawnWorker(bootLogger)));
bootLogger.info('All workers started');
}
function spawnWorker(): Promise<void> {
function spawnWorker(bootLogger: Logger): Promise<void> {
return new Promise(res => {
const worker = cluster.fork();
worker.on('message', message => {

View file

@ -4,14 +4,16 @@
*/
import cluster from 'node:cluster';
import * as Sentry from '@sentry/node';
import { nodeProfilingIntegration } from '@sentry/profiling-node';
import { envOption } from '@/env.js';
import { loadConfig } from '@/config.js';
import { jobQueue, server } from './common.js';
import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';
import * as fs from 'node:fs';
import * as Sentry from '@sentry/node';
import { nodeProfilingIntegration } from '@sentry/profiling-node';
import { loadConfig } from '@/config.js';
import type { LoggerService } from '@/core/LoggerService.js';
import type { EnvService } from '@/global/EnvService.js';
import { jobQueue, server } from './common.js';
const _filename = fileURLToPath(import.meta.url);
const _dirname = dirname(_filename);
const meta = JSON.parse(fs.readFileSync(`${_dirname}/../../../../built/meta.json`, 'utf-8'));
@ -19,8 +21,9 @@ const meta = JSON.parse(fs.readFileSync(`${_dirname}/../../../../built/meta.json
/**
* Init worker process
*/
export async function workerMain() {
const config = loadConfig();
export async function workerMain(loggerService: LoggerService, envService: EnvService) {
const config = loadConfig(loggerService);
const envOption = envService.options;
if (config.sentryForBackend) {
Sentry.init({
@ -37,7 +40,7 @@ export async function workerMain() {
maxBreadcrumbs: 0,
// Set release version
release: "Sharkey@" + (meta.gitVersion ?? meta.version),
release: 'Sharkey@' + (meta.gitVersion ?? meta.version),
...config.sentryForBackend.options,
});