diff --git a/api/dev/states/myservers.cfg b/api/dev/states/myservers.cfg index 51d0baecb..9797b2a09 100644 --- a/api/dev/states/myservers.cfg +++ b/api/dev/states/myservers.cfg @@ -21,4 +21,4 @@ dynamicRemoteAccessType="DISABLED" [upc] apikey="unupc_fab6ff6ffe51040595c6d9ffb63a353ba16cc2ad7d93f813a2e80a5810" [connectionStatus] -minigraph="PRE_INIT" +minigraph="ERROR_RETRYING" diff --git a/api/ecosystem.config.json b/api/ecosystem.config.json index e82d923f7..ffa0d3142 100644 --- a/api/ecosystem.config.json +++ b/api/ecosystem.config.json @@ -3,8 +3,9 @@ { "name": "unraid-api", "script": "npm", - "args": "run tsx:unraid -- boot", - "instances": 1 + "args": "run boot:unraid", + "log": "/var/log/unraid-api/unraid-api.log", + "exec_mode": "fork" } ] -} \ No newline at end of file +} diff --git a/api/package.json b/api/package.json index 85e0e6346..3c231db7a 100644 --- a/api/package.json +++ b/api/package.json @@ -22,6 +22,7 @@ "release": "standard-version", "typesync": "typesync", "install:unraid": "./scripts/install-in-unraid.sh", + "boot:unraid": "tsx -r dotenv/config src/index.ts", "tsx:unraid": "tsx -r dotenv/config src/cli.ts", "start:plugin": "INTROSPECTION=true LOG_MOTHERSHIP_MESSAGES=true LOG_TYPE=pretty LOG_LEVEL=trace unraid-api start --debug", "start:plugin-verbose": "LOG_CONTEXT=true LOG_MOTHERSHIP_MESSAGES=true LOG_TYPE=pretty LOG_LEVEL=trace unraid-api start --debug", @@ -35,7 +36,7 @@ "start:local": "./scripts/dc.sh run --rm --service-ports local", "start:ddev": "./scripts/dc.sh run --rm --service-ports dev", "start:dtest": "./scripts/dc.sh run --rm builder npm run test", - "enter:ddev": "./scripts/dc.sh exec dev /bin/sh" + "enter:ddev": "./scripts/dc.sh exec dev /bin/bash" }, "files": [ ".env.staging", diff --git a/api/src/cli/commands/boot.ts b/api/src/cli/commands/boot.ts index a53d6c2e3..1dfe8a52f 100644 --- a/api/src/cli/commands/boot.ts +++ b/api/src/cli/commands/boot.ts @@ -1,7 +1,5 @@ import { internalLogger } from '@app/core/index'; -import {startApp} from '@app/index'; +import { startApp } from '@app/index'; +await startApp(); + -export const boot = async () => { - internalLogger.info('Booting Unraid API'); - await startApp(); -} \ No newline at end of file diff --git a/api/src/cli/commands/start.ts b/api/src/cli/commands/start.ts index 08c75e66c..ded5641e7 100644 --- a/api/src/cli/commands/start.ts +++ b/api/src/cli/commands/start.ts @@ -7,6 +7,6 @@ import { execSync } from 'child_process'; export const start = async () => { cliLogger.info('Starting unraid-api@v%s', API_VERSION); - execSync('pm2 start ecosystem.config.json --update-env', { env: process.env }); + execSync('pm2 start ecosystem.config.json --update-env', { env: process.env, stdio: 'inherit' }); // Start API }; diff --git a/api/src/cli/commands/stop.ts b/api/src/cli/commands/stop.ts index 9f8bbc489..a98da3503 100644 --- a/api/src/cli/commands/stop.ts +++ b/api/src/cli/commands/stop.ts @@ -1,5 +1,5 @@ import { execSync } from 'child_process'; export const stop = async () => { - execSync('pm2 stop unraid-api'); + execSync('pm2 stop unraid-api', { stdio: 'inherit' }); }; diff --git a/api/src/cli/index.ts b/api/src/cli/index.ts index f5d7b07bb..57bc426e5 100755 --- a/api/src/cli/index.ts +++ b/api/src/cli/index.ts @@ -45,7 +45,6 @@ export const main = async (...argv: string[]) => { const commands = { start: import('@app/cli/commands/start').then((pkg) => pkg.start), stop: import('@app/cli/commands/stop').then((pkg) => pkg.stop), - boot: import('@app/cli/commands/boot').then((pkg) => pkg.boot), restart: import('@app/cli/commands/restart').then((pkg) => pkg.restart), 'switch-env': import('@app/cli/commands/switch-env').then((pkg) => pkg.switchEnv), version: import('@app/cli/commands/version').then((pkg) => pkg.version), diff --git a/api/src/core/log.ts b/api/src/core/log.ts index ab23b3ec5..79e040d8e 100644 --- a/api/src/core/log.ts +++ b/api/src/core/log.ts @@ -1,34 +1,7 @@ import { pino } from 'pino'; -import { LOG_TRANSPORT, LOG_TYPE } from '@app/environment'; +import { LOG_TYPE } from '@app/environment'; import pretty from 'pino-pretty'; -import { chmodSync, existsSync, mkdirSync, rmSync, statSync } from 'node:fs'; -import { getters } from '@app/store/index'; -import { join } from 'node:path'; - -const makeLoggingDirectoryIfNotExists = () => { - if (!existsSync(getters.paths()['log-base'])) { - console.log('Creating logging directory'); - mkdirSync(getters.paths()['log-base']); - } - - chmodSync(getters.paths()['log-base'], 0o644); - if ( - existsSync(`${getters.paths()['log-base']}/stdout.log`) && - statSync(`${getters.paths()['log-base']}/stdout.log`).size > 5_000_000 - ) { - rmSync(`${getters.paths()['log-base']}/stdout.log`); - } - try { - rmSync(`${getters.paths()['log-base']}/stdout.log.*`); - } catch (e) { - // Ignore Error - } -}; - -if (LOG_TRANSPORT === 'file') { - makeLoggingDirectoryIfNotExists(); -} export const levels = [ 'trace', @@ -47,12 +20,8 @@ const level = ] ?? 'info'; export const logDestination = pino.destination({ - dest: - LOG_TRANSPORT === 'file' - ? join(getters.paths()['log-base'], 'stdout.log') - : 1, minLength: 1_024, - sync: false, + sync: true, }); const stream = @@ -112,30 +81,3 @@ export const loggers = [ remoteQueryLogger, apiLogger, ]; - -// Send SIGUSR1 to increase log level -process.on('SIGUSR1', () => { - const level = logger.level; - const nextLevel = - levels[levels.findIndex((_level) => _level === level) + 1] ?? levels[0]; - loggers.forEach((logger) => { - logger.level = nextLevel; - }); - internalLogger.info({ - message: `Log level changed from ${level} to ${nextLevel}`, - }); -}); - -// Send SIGUSR1 to decrease log level -process.on('SIGUSR2', () => { - const level = logger.level; - const nextLevel = - levels[levels.findIndex((_level) => _level === level) - 1] ?? - levels[levels.length - 1]; - loggers.forEach((logger) => { - logger.level = nextLevel; - }); - internalLogger.info({ - message: `Log level changed from ${level} to ${nextLevel}`, - }); -}); diff --git a/api/src/index.ts b/api/src/index.ts index efa2d3957..10647047c 100644 --- a/api/src/index.ts +++ b/api/src/index.ts @@ -38,85 +38,83 @@ const unlinkUnixPort = () => { } }; -export const startApp = async () => { - try { - environment.IS_MAIN_PROCESS = true; +try { + environment.IS_MAIN_PROCESS = true; - logger.debug('ENV %o', env); + logger.debug('ENV %o', env); - const cacheable = new CacheableLookup(); + const cacheable = new CacheableLookup(); - Object.assign(global, { WebSocket }); - // Ensure all DNS lookups are cached for their TTL - cacheable.install(http.globalAgent); - cacheable.install(https.globalAgent); + Object.assign(global, { WebSocket }); + // Ensure all DNS lookups are cached for their TTL + cacheable.install(http.globalAgent); + cacheable.install(https.globalAgent); - // Start file <-> store sync - // Must occur before config is loaded to ensure that the handler can fix broken configs - await startStoreSync(); + // Start file <-> store sync + // Must occur before config is loaded to ensure that the handler can fix broken configs + await startStoreSync(); - await setupLogRotation(); + await setupLogRotation(); - // Load my servers config file into store - await store.dispatch(loadConfigFile()); + // Load my servers config file into store + await store.dispatch(loadConfigFile()); - // Load emhttp state into store - await store.dispatch(loadStateFiles()); + // Load emhttp state into store + await store.dispatch(loadStateFiles()); - // Load initial registration key into store - await store.dispatch(loadRegistrationKey()); + // Load initial registration key into store + await store.dispatch(loadRegistrationKey()); - // Load my dynamix config file into store - await store.dispatch(loadDynamixConfigFile()); + // Load my dynamix config file into store + await store.dispatch(loadDynamixConfigFile()); - // Start listening to file updates - StateManager.getInstance(); + // Start listening to file updates + StateManager.getInstance(); - // Start listening to key file changes - setupRegistrationKeyWatch(); + // Start listening to key file changes + setupRegistrationKeyWatch(); - // Start listening to docker events - setupVarRunWatch(); + // Start listening to docker events + setupVarRunWatch(); - // Start listening to dynamix config file changes - setupDynamixConfigWatch(); + // Start listening to dynamix config file changes + setupDynamixConfigWatch(); - // Disabled until we need the access token to work - // TokenRefresh.init(); + // Disabled until we need the access token to work + // TokenRefresh.init(); - // If port is unix socket, delete old socket before starting http server + // If port is unix socket, delete old socket before starting http server + unlinkUnixPort(); + + // Start webserver + server = await bootstrapNestServer(); + PingTimeoutJobs.init(); + + startMiddlewareListeners(); + + await validateApiKeyIfPresent(); + + // On process exit stop HTTP server - this says it supports async but it doesnt seem to + exitHook(() => { + console.log('exithook'); + server?.close?.(); + // If port is unix socket, delete socket before exiting unlinkUnixPort(); - // Start webserver - server = await bootstrapNestServer(); - PingTimeoutJobs.init(); - - startMiddlewareListeners(); - - await validateApiKeyIfPresent(); - - // On process exit stop HTTP server - this says it supports async but it doesnt seem to - exitHook(() => { - console.log('exithook'); - server?.close?.(); - // If port is unix socket, delete socket before exiting - unlinkUnixPort(); - - shutdownApiEvent(); - - process.exit(0); - }); - // Start a loop to run the app - await new Promise(() => {}); - } catch (error: unknown) { - if (error instanceof Error) { - logger.error('API-ERROR %s %s', error.message, error.stack); - } - if (server) { - await server?.close?.(); - } shutdownApiEvent(); - // Kill application - process.exit(1); + + process.exit(0); + }); + // Start a loop to run the app + await new Promise(() => {}); +} catch (error: unknown) { + if (error instanceof Error) { + logger.error('API-ERROR %s %s', error.message, error.stack); } -}; + if (server) { + await server?.close?.(); + } + shutdownApiEvent(); + // Kill application + process.exit(1); +}