feat: better pm2 calls, log lines

This commit is contained in:
Eli Bosley
2025-01-17 14:44:24 -05:00
parent 7fa849d2a0
commit 33dd90af04
5 changed files with 78 additions and 25 deletions

View File

@@ -1,5 +1,5 @@
import { PORT } from '@app/environment'; import { PORT } from '@app/environment';
import { type JSONWebKeySet } from 'jose'; import type { JSONWebKeySet } from 'jose';
import { join } from 'path'; import { join } from 'path';
export const getInternalApiAddress = (isHttp = true, nginxPort = 80) => { export const getInternalApiAddress = (isHttp = true, nginxPort = 80) => {
@@ -81,4 +81,5 @@ export const KEYSERVER_VALIDATION_ENDPOINT =
/** Set the max retries for the GraphQL Client */ /** Set the max retries for the GraphQL Client */
export const MAX_RETRIES_FOR_LINEAR_BACKOFF = 100; export const MAX_RETRIES_FOR_LINEAR_BACKOFF = 100;
export const PM2_PATH = join(import.meta.dirname, '../../', 'node_modules', '.bin', 'pm2'); export const PM2_PATH = join(import.meta.dirname, '../../', 'node_modules', '.bin', 'pm2');
export const ECOSYSTEM_PATH = join(import.meta.dirname, '../../', 'ecosystem.config.json');

View File

@@ -10,6 +10,7 @@ import { SwitchEnvCommand } from '@app/unraid-api/cli/switch-env.command';
import { VersionCommand } from '@app/unraid-api/cli/version.command'; import { VersionCommand } from '@app/unraid-api/cli/version.command';
import { StatusCommand } from '@app/unraid-api/cli/status.command'; import { StatusCommand } from '@app/unraid-api/cli/status.command';
import { ValidateTokenCommand } from '@app/unraid-api/cli/validate-token.command'; import { ValidateTokenCommand } from '@app/unraid-api/cli/validate-token.command';
import { LogsCommand } from '@app/unraid-api/cli/logs.command';
@Module({ @Module({
providers: [ providers: [
@@ -22,7 +23,8 @@ import { ValidateTokenCommand } from '@app/unraid-api/cli/validate-token.command
SwitchEnvCommand, SwitchEnvCommand,
VersionCommand, VersionCommand,
StatusCommand, StatusCommand,
ValidateTokenCommand ValidateTokenCommand,
LogsCommand
], ],
}) })
export class CliModule {} export class CliModule {}

View File

@@ -0,0 +1,37 @@
import { execa } from 'execa';
import { Command, CommandRunner, Option } from 'nest-commander';
import { ECOSYSTEM_PATH, PM2_PATH } from '@app/consts';
import { LogService } from '@app/unraid-api/cli/log.service';
interface LogsOptions {
lines: number
}
@Command({ name: 'logs' })
export class LogsCommand extends CommandRunner {
constructor(private readonly logger: LogService) {
super();
}
@Option({ flags: '-l, --lines', description: 'Number of lines to tail'})
parseLines(input: string): number
{
return isNaN(parseInt(input)) ? 100 : parseInt(input)
}
async run(passedParams: string[], options?: LogsOptions): Promise<void> {
const lines = options?.lines ?? 100;
const subprocess = execa(PM2_PATH, ['logs', ECOSYSTEM_PATH, '--lines', lines.toString()]);
subprocess.stdout?.on('data', (data) => {
this.logger.log(data.toString());
});
subprocess.stderr?.on('data', (data) => {
this.logger.error(data.toString());
});
await subprocess;
}
}

View File

@@ -1,22 +1,38 @@
import { PM2_PATH } from '@app/consts';
import { execSync } from 'child_process'; import { execSync } from 'child_process';
import { Command, CommandRunner } from 'nest-commander';
import { join } from 'path'; import { join } from 'path';
import { Command, CommandRunner } from 'nest-commander';
import { ECOSYSTEM_PATH, PM2_PATH } from '@app/consts';
/** /**
* Stop a running API process and then start it again. * Stop a running API process and then start it again.
*/ */
@Command({ name: 'restart', description: 'Restart / Start the Unraid API'}) @Command({ name: 'restart', description: 'Restart / Start the Unraid API'})
export class RestartCommand extends CommandRunner { export class RestartCommand extends CommandRunner {
async run(_): Promise<void> { async run(_): Promise<void> {
console.log(
'Dirname is ',
import.meta.dirname,
' command is ',
`${PM2_PATH} restart ${ECOSYSTEM_PATH} --update-env`
);
execSync( execSync(
`${PM2_PATH} restart ${join(import.meta.dirname, '../../', 'ecosystem.config.json')} --update-env`, `${PM2_PATH} restart ${ECOSYSTEM_PATH} --update-env`,
{ {
env: process.env, env: process.env,
stdio: 'inherit', stdio: 'pipe',
cwd: process.cwd(), cwd: process.cwd(),
} }
); );
} }
} }

View File

@@ -1,9 +1,10 @@
import { execSync } from 'child_process'; import { execSync } from 'child_process';
import { join } from 'path'; import { join } from 'path';
import { execa } from 'execa';
import { Command, CommandRunner, Option } from 'nest-commander'; import { Command, CommandRunner, Option } from 'nest-commander';
import { PM2_PATH } from '@app/consts'; import { ECOSYSTEM_PATH, PM2_PATH } from '@app/consts';
import { levels } from '@app/core/log'; import { levels } from '@app/core/log';
import { LogService } from '@app/unraid-api/cli/log.service'; import { LogService } from '@app/unraid-api/cli/log.service';
@@ -21,27 +22,23 @@ export class StartCommand extends CommandRunner {
} }
async run(_, options: StartCommandOptions): Promise<void> { async run(_, options: StartCommandOptions): Promise<void> {
this.logger.debug(options); this.logger.info('Starting the Unraid API');
this.logger.log( const envLog = options['log-level'] ? `LOG_LEVEL=${options['log-level']}` : ''
`Starting unraid-api with command: const { stderr, stdout } = await execa(`${envLog} ${PM2_PATH}`.trim(), ['start', ECOSYSTEM_PATH, '--update-env']);
${PM2_PATH} start ${join(import.meta.dirname, 'ecosystem.config.json')} --update-env` if (stdout) {
); this.logger.log(stdout);
}
execSync( if (stderr) {
`${PM2_PATH} start ${join(import.meta.dirname, '../../', 'ecosystem.config.json')} --update-env`, this.logger.error(stderr);
{ process.exit(1);
env: process.env, }
stdio: 'inherit',
cwd: process.cwd(),
}
);
} }
@Option({ @Option({
flags: '--log-level [string]', flags: `--log-level <${levels.join('|')}>`,
description: 'log level to use', description: 'log level to use',
}) })
parseLogLevel(val: unknown): typeof levels { parseLogLevel(val: string): typeof levels {
return (levels.includes(val as (typeof levels)[number]) return (levels.includes(val as (typeof levels)[number])
? (val as (typeof levels)[number]) ? (val as (typeof levels)[number])
: 'info') as unknown as typeof levels; : 'info') as unknown as typeof levels;