Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(server): worker env #13160

Merged
merged 1 commit into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading