mirror of
https://github.com/immich-app/immich.git
synced 2024-11-24 08:52:28 +02:00
refactor(server): worker env (#13160)
This commit is contained in:
parent
892a35acb5
commit
db1623f43f
@ -1,3 +1,3 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
node /usr/src/app/dist/utils/healthcheck.js
|
node /usr/src/app/dist/bin/healthcheck.js
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
"check": "tsc --noEmit",
|
"check": "tsc --noEmit",
|
||||||
"check:code": "npm run format && npm run lint && npm run check",
|
"check:code": "npm run format && npm run lint && npm run check",
|
||||||
"check:all": "npm run check:code && npm run test:cov",
|
"check:all": "npm run check:code && npm run test:cov",
|
||||||
"healthcheck": "node ./dist/utils/healthcheck.js",
|
|
||||||
"test": "vitest",
|
"test": "vitest",
|
||||||
"test:watch": "vitest --watch",
|
"test:watch": "vitest --watch",
|
||||||
"test:cov": "vitest --coverage",
|
"test:cov": "vitest --coverage",
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
const port = Number(process.env.IMMICH_PORT) || 3001;
|
import { ImmichWorker } from 'src/enum';
|
||||||
const controller = new AbortController();
|
import { ConfigRepository } from 'src/repositories/config.repository';
|
||||||
|
|
||||||
const main = async () => {
|
const main = async () => {
|
||||||
if (!process.env.IMMICH_WORKERS_INCLUDE?.includes('api')) {
|
const { workers, port } = new ConfigRepository().getEnv();
|
||||||
|
if (!workers.includes(ImmichWorker.API)) {
|
||||||
process.exit();
|
process.exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const controller = new AbortController();
|
||||||
const timeout = setTimeout(() => controller.abort(), 2000);
|
const timeout = setTimeout(() => controller.abort(), 2000);
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`http://localhost:${port}/api/server-info/ping`, {
|
const response = await fetch(`http://localhost:${port}/api/server-info/ping`, {
|
@ -334,3 +334,8 @@ export enum ImmichEnvironment {
|
|||||||
TESTING = 'testing',
|
TESTING = 'testing',
|
||||||
PRODUCTION = 'production',
|
PRODUCTION = 'production',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum ImmichWorker {
|
||||||
|
API = 'api',
|
||||||
|
MICROSERVICES = 'microservices',
|
||||||
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { ImmichEnvironment, LogLevel } from 'src/enum';
|
import { ImmichEnvironment, ImmichWorker, LogLevel } from 'src/enum';
|
||||||
import { VectorExtension } from 'src/interfaces/database.interface';
|
import { VectorExtension } from 'src/interfaces/database.interface';
|
||||||
|
|
||||||
export const IConfigRepository = 'IConfigRepository';
|
export const IConfigRepository = 'IConfigRepository';
|
||||||
@ -18,6 +18,8 @@ export interface EnvData {
|
|||||||
ignoreMountCheckErrors: boolean;
|
ignoreMountCheckErrors: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
workers: ImmichWorker[];
|
||||||
|
|
||||||
nodeVersion?: string;
|
nodeVersion?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,20 +2,15 @@ import { CommandFactory } from 'nest-commander';
|
|||||||
import { fork } from 'node:child_process';
|
import { fork } from 'node:child_process';
|
||||||
import { Worker } from 'node:worker_threads';
|
import { Worker } from 'node:worker_threads';
|
||||||
import { ImmichAdminModule } from 'src/app.module';
|
import { ImmichAdminModule } from 'src/app.module';
|
||||||
import { LogLevel } from 'src/enum';
|
import { ImmichWorker, LogLevel } from 'src/enum';
|
||||||
import { getWorkers } from 'src/utils/workers';
|
import { ConfigRepository } from 'src/repositories/config.repository';
|
||||||
const immichApp = process.argv[2] || process.env.IMMICH_APP;
|
|
||||||
|
|
||||||
if (process.argv[2] === immichApp) {
|
const immichApp = process.argv[2];
|
||||||
|
if (immichApp) {
|
||||||
process.argv.splice(2, 1);
|
process.argv.splice(2, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function bootstrapImmichAdmin() {
|
function bootstrapWorker(name: ImmichWorker) {
|
||||||
process.env.IMMICH_LOG_LEVEL = LogLevel.WARN;
|
|
||||||
await CommandFactory.run(ImmichAdminModule);
|
|
||||||
}
|
|
||||||
|
|
||||||
function bootstrapWorker(name: string) {
|
|
||||||
console.log(`Starting ${name} worker`);
|
console.log(`Starting ${name} worker`);
|
||||||
|
|
||||||
const execArgv = process.execArgv.map((arg) => (arg.startsWith('--inspect') ? '--inspect=0.0.0.0:9231' : arg));
|
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() {
|
function bootstrap() {
|
||||||
switch (immichApp) {
|
if (immichApp === 'immich-admin') {
|
||||||
case 'immich-admin': {
|
process.title = 'immich_admin_cli';
|
||||||
process.title = 'immich_admin_cli';
|
process.env.IMMICH_LOG_LEVEL = LogLevel.WARN;
|
||||||
return bootstrapImmichAdmin();
|
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';
|
process.title = 'immich';
|
||||||
for (const worker of getWorkers()) {
|
const { workers } = new ConfigRepository().getEnv();
|
||||||
|
for (const worker of workers) {
|
||||||
bootstrapWorker(worker);
|
bootstrapWorker(worker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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', () => {
|
describe('getWorkers', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
@ -1,13 +1,30 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { getVectorExtension } from 'src/database.config';
|
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 { EnvData, IConfigRepository } from 'src/interfaces/config.interface';
|
||||||
|
import { setDifference } from 'src/utils/set';
|
||||||
|
|
||||||
// TODO replace src/config validation with class-validator, here
|
// 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()
|
@Injectable()
|
||||||
export class ConfigRepository implements IConfigRepository {
|
export class ConfigRepository implements IConfigRepository {
|
||||||
getEnv(): EnvData {
|
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 {
|
return {
|
||||||
port: Number(process.env.IMMICH_PORT) || 3001,
|
port: Number(process.env.IMMICH_PORT) || 3001,
|
||||||
environment: process.env.IMMICH_ENV as ImmichEnvironment,
|
environment: process.env.IMMICH_ENV as ImmichEnvironment,
|
||||||
@ -20,6 +37,7 @@ export class ConfigRepository implements IConfigRepository {
|
|||||||
storage: {
|
storage: {
|
||||||
ignoreMountCheckErrors: process.env.IMMICH_IGNORE_MOUNT_CHECK_ERRORS === 'true',
|
ignoreMountCheckErrors: process.env.IMMICH_IGNORE_MOUNT_CHECK_ERRORS === 'true',
|
||||||
},
|
},
|
||||||
|
workers,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
|
||||||
};
|
|
@ -1,4 +1,4 @@
|
|||||||
import { ImmichEnvironment } from 'src/enum';
|
import { ImmichEnvironment, ImmichWorker } from 'src/enum';
|
||||||
import { EnvData, IConfigRepository } from 'src/interfaces/config.interface';
|
import { EnvData, IConfigRepository } from 'src/interfaces/config.interface';
|
||||||
import { DatabaseExtension } from 'src/interfaces/database.interface';
|
import { DatabaseExtension } from 'src/interfaces/database.interface';
|
||||||
import { Mocked, vitest } from 'vitest';
|
import { Mocked, vitest } from 'vitest';
|
||||||
@ -15,6 +15,8 @@ const envData: EnvData = {
|
|||||||
storage: {
|
storage: {
|
||||||
ignoreMountCheckErrors: false,
|
ignoreMountCheckErrors: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
workers: [ImmichWorker.API, ImmichWorker.MICROSERVICES],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const newConfigRepositoryMock = (): Mocked<IConfigRepository> => {
|
export const newConfigRepositoryMock = (): Mocked<IConfigRepository> => {
|
||||||
|
Loading…
Reference in New Issue
Block a user