Skip to content

Commit

Permalink
refactor(server): worker env (immich-app#13160)
Browse files Browse the repository at this point in the history
  • Loading branch information
jrasm91 authored Oct 3, 2024
1 parent 892a35a commit db1623f
Show file tree
Hide file tree
Showing 10 changed files with 63 additions and 58 deletions.
2 changes: 1 addition & 1 deletion server/bin/immich-healthcheck
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#!/usr/bin/env bash

node /usr/src/app/dist/utils/healthcheck.js
node /usr/src/app/dist/bin/healthcheck.js
1 change: 0 additions & 1 deletion server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
@@ -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`, {
Expand Down
5 changes: 5 additions & 0 deletions server/src/enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -334,3 +334,8 @@ export enum ImmichEnvironment {
TESTING = 'testing',
PRODUCTION = 'production',
}

export enum ImmichWorker {
API = 'api',
MICROSERVICES = 'microservices',
}
4 changes: 3 additions & 1 deletion server/src/interfaces/config.interface.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -18,6 +18,8 @@ export interface EnvData {
ignoreMountCheckErrors: boolean;
};

workers: ImmichWorker[];

nodeVersion?: string;
}

Expand Down
52 changes: 24 additions & 28 deletions server/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -35,26 +30,27 @@ function bootstrapWorker(name: string) {
}

function bootstrap() {
switch (immichApp) {
case 'immich-admin': {
process.title = 'immich_admin_cli';
return bootstrapImmichAdmin();
}
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-admin') {
process.title = 'immich_admin_cli';
process.env.IMMICH_LOG_LEVEL = LogLevel.WARN;
return CommandFactory.run(ImmichAdminModule);
}

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);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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(() => {
Expand Down
20 changes: 19 additions & 1 deletion server/src/repositories/config.repository.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -20,6 +37,7 @@ export class ConfigRepository implements IConfigRepository {
storage: {
ignoreMountCheckErrors: process.env.IMMICH_IGNORE_MOUNT_CHECK_ERRORS === 'true',
},
workers,
};
}
}
21 changes: 0 additions & 21 deletions server/src/utils/workers.ts

This file was deleted.

4 changes: 3 additions & 1 deletion server/test/repositories/config.repository.mock.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -15,6 +15,8 @@ const envData: EnvData = {
storage: {
ignoreMountCheckErrors: false,
},

workers: [ImmichWorker.API, ImmichWorker.MICROSERVICES],
};

export const newConfigRepositoryMock = (): Mocked<IConfigRepository> => {
Expand Down

0 comments on commit db1623f

Please sign in to comment.