1
0
mirror of https://github.com/immich-app/immich.git synced 2024-11-21 18:16:55 +02:00

refactor(server): worker env (#13160)

This commit is contained in:
Jason Rasmussen 2024-10-03 15:28:36 -04:00 committed by GitHub
parent 892a35acb5
commit db1623f43f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 63 additions and 58 deletions

View File

@ -1,3 +1,3 @@
#!/usr/bin/env bash
node /usr/src/app/dist/utils/healthcheck.js
node /usr/src/app/dist/bin/healthcheck.js

View File

@ -18,7 +18,6 @@
"check": "tsc --noEmit",
"check:code": "npm run format && npm run lint && npm run check",
"check:all": "npm run check:code && npm run test:cov",
"healthcheck": "node ./dist/utils/healthcheck.js",
"test": "vitest",
"test:watch": "vitest --watch",
"test:cov": "vitest --coverage",

View File

@ -1,12 +1,14 @@
#!/usr/bin/env node
const port = Number(process.env.IMMICH_PORT) || 3001;
const controller = new AbortController();
import { ImmichWorker } from 'src/enum';
import { ConfigRepository } from 'src/repositories/config.repository';
const main = async () => {
if (!process.env.IMMICH_WORKERS_INCLUDE?.includes('api')) {
const { workers, port } = new ConfigRepository().getEnv();
if (!workers.includes(ImmichWorker.API)) {
process.exit();
}
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 2000);
try {
const response = await fetch(`http://localhost:${port}/api/server-info/ping`, {

View File

@ -334,3 +334,8 @@ export enum ImmichEnvironment {
TESTING = 'testing',
PRODUCTION = 'production',
}
export enum ImmichWorker {
API = 'api',
MICROSERVICES = 'microservices',
}

View File

@ -1,4 +1,4 @@
import { ImmichEnvironment, LogLevel } from 'src/enum';
import { ImmichEnvironment, ImmichWorker, LogLevel } from 'src/enum';
import { VectorExtension } from 'src/interfaces/database.interface';
export const IConfigRepository = 'IConfigRepository';
@ -18,6 +18,8 @@ export interface EnvData {
ignoreMountCheckErrors: boolean;
};
workers: ImmichWorker[];
nodeVersion?: string;
}

View File

@ -2,20 +2,15 @@ import { CommandFactory } from 'nest-commander';
import { fork } from 'node:child_process';
import { Worker } from 'node:worker_threads';
import { ImmichAdminModule } from 'src/app.module';
import { LogLevel } from 'src/enum';
import { getWorkers } from 'src/utils/workers';
const immichApp = process.argv[2] || process.env.IMMICH_APP;
import { ImmichWorker, LogLevel } from 'src/enum';
import { ConfigRepository } from 'src/repositories/config.repository';
if (process.argv[2] === immichApp) {
const immichApp = process.argv[2];
if (immichApp) {
process.argv.splice(2, 1);
}
async function bootstrapImmichAdmin() {
process.env.IMMICH_LOG_LEVEL = LogLevel.WARN;
await CommandFactory.run(ImmichAdminModule);
}
function bootstrapWorker(name: string) {
function bootstrapWorker(name: ImmichWorker) {
console.log(`Starting ${name} worker`);
const execArgv = process.execArgv.map((arg) => (arg.startsWith('--inspect') ? '--inspect=0.0.0.0:9231' : arg));
@ -35,26 +30,27 @@ function bootstrapWorker(name: string) {
}
function bootstrap() {
switch (immichApp) {
case 'immich-admin': {
if (immichApp === 'immich-admin') {
process.title = 'immich_admin_cli';
return bootstrapImmichAdmin();
process.env.IMMICH_LOG_LEVEL = LogLevel.WARN;
return CommandFactory.run(ImmichAdminModule);
}
case 'immich': {
if (!process.env.IMMICH_WORKERS_INCLUDE) {
process.env.IMMICH_WORKERS_INCLUDE = 'api';
}
break;
}
case 'microservices': {
if (!process.env.IMMICH_WORKERS_INCLUDE) {
process.env.IMMICH_WORKERS_INCLUDE = 'microservices';
}
break;
if (immichApp === 'immich' || immichApp === 'microservices') {
console.error(
`Using "start.sh ${immichApp}" has been deprecated. See https://github.com/immich-app/immich/releases/tag/v1.118.0 for more information.`,
);
process.exit(1);
}
if (immichApp) {
console.error(`Unknown command: "${immichApp}"`);
process.exit(1);
}
process.title = 'immich';
for (const worker of getWorkers()) {
const { workers } = new ConfigRepository().getEnv();
for (const worker of workers) {
bootstrapWorker(worker);
}
}

View File

@ -1,4 +1,6 @@
import { getWorkers } from 'src/utils/workers';
import { ConfigRepository } from 'src/repositories/config.repository';
const getWorkers = () => new ConfigRepository().getEnv().workers;
describe('getWorkers', () => {
beforeEach(() => {

View File

@ -1,13 +1,30 @@
import { Injectable } from '@nestjs/common';
import { getVectorExtension } from 'src/database.config';
import { ImmichEnvironment, LogLevel } from 'src/enum';
import { ImmichEnvironment, ImmichWorker, LogLevel } from 'src/enum';
import { EnvData, IConfigRepository } from 'src/interfaces/config.interface';
import { setDifference } from 'src/utils/set';
// TODO replace src/config validation with class-validator, here
const WORKER_TYPES = new Set(Object.values(ImmichWorker));
const asSet = (value: string | undefined, defaults: ImmichWorker[]) => {
const values = (value || '').replaceAll(/\s/g, '').split(',').filter(Boolean);
return new Set(values.length === 0 ? defaults : (values as ImmichWorker[]));
};
@Injectable()
export class ConfigRepository implements IConfigRepository {
getEnv(): EnvData {
const included = asSet(process.env.IMMICH_WORKERS_INCLUDE, [ImmichWorker.API, ImmichWorker.MICROSERVICES]);
const excluded = asSet(process.env.IMMICH_WORKERS_EXCLUDE, []);
const workers = [...setDifference(included, excluded)];
for (const worker of workers) {
if (!WORKER_TYPES.has(worker)) {
throw new Error(`Invalid worker(s) found: ${workers.join(',')}`);
}
}
return {
port: Number(process.env.IMMICH_PORT) || 3001,
environment: process.env.IMMICH_ENV as ImmichEnvironment,
@ -20,6 +37,7 @@ export class ConfigRepository implements IConfigRepository {
storage: {
ignoreMountCheckErrors: process.env.IMMICH_IGNORE_MOUNT_CHECK_ERRORS === 'true',
},
workers,
};
}
}

View File

@ -1,21 +0,0 @@
const WORKER_TYPES = new Set(['api', 'microservices']);
export const getWorkers = () => {
let workers = ['api', 'microservices'];
const includedWorkers = process.env.IMMICH_WORKERS_INCLUDE?.replaceAll(/\s/g, '');
const excludedWorkers = process.env.IMMICH_WORKERS_EXCLUDE?.replaceAll(/\s/g, '');
if (includedWorkers) {
workers = includedWorkers.split(',');
}
if (excludedWorkers) {
workers = workers.filter((worker) => !excludedWorkers.split(',').includes(worker));
}
if (workers.some((worker) => !WORKER_TYPES.has(worker))) {
throw new Error(`Invalid worker(s) found: ${workers}`);
}
return workers;
};

View File

@ -1,4 +1,4 @@
import { ImmichEnvironment } from 'src/enum';
import { ImmichEnvironment, ImmichWorker } from 'src/enum';
import { EnvData, IConfigRepository } from 'src/interfaces/config.interface';
import { DatabaseExtension } from 'src/interfaces/database.interface';
import { Mocked, vitest } from 'vitest';
@ -15,6 +15,8 @@ const envData: EnvData = {
storage: {
ignoreMountCheckErrors: false,
},
workers: [ImmichWorker.API, ImmichWorker.MICROSERVICES],
};
export const newConfigRepositoryMock = (): Mocked<IConfigRepository> => {