Skip to content

Commit

Permalink
feat: add cortex serve detach option - add health check and stop api …
Browse files Browse the repository at this point in the history
…endpoints
  • Loading branch information
louis-jan committed Jun 15, 2024
1 parent fa82078 commit eed17d3
Show file tree
Hide file tree
Showing 12 changed files with 137 additions and 15 deletions.
20 changes: 19 additions & 1 deletion cortex-js/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ import { AppLoggerMiddleware } from './infrastructure/middlewares/app.logger.mid
import { EventEmitterModule } from '@nestjs/event-emitter';
import { DownloadManagerModule } from './download-manager/download-manager.module';
import { EventsController } from './infrastructure/controllers/events.controller';
import { AppController } from './infrastructure/controllers/app.controller';
import { AssistantsController } from './infrastructure/controllers/assistants.controller';
import { ChatController } from './infrastructure/controllers/chat.controller';
import { EmbeddingsController } from './infrastructure/controllers/embeddings.controller';
import { ModelsController } from './infrastructure/controllers/models.controller';
import { ThreadsController } from './infrastructure/controllers/threads.controller';
import { StatusController } from './infrastructure/controllers/status.controller';
import { ProcessController } from './infrastructure/controllers/process.controller';

@Module({
imports: [
Expand All @@ -40,7 +48,17 @@ import { EventsController } from './infrastructure/controllers/events.controller
ModelRepositoryModule,
DownloadManagerModule,
],
controllers: [EventsController],
controllers: [
AppController,
AssistantsController,
ChatController,
EmbeddingsController,
ModelsController,
ThreadsController,
StatusController,
ProcessController,
EventsController,
],
providers: [SeedService],
})
export class AppModule implements NestModule {
Expand Down
8 changes: 7 additions & 1 deletion cortex-js/src/infrastructure/commanders/ps.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ export class PSCommand extends CommandRunner {
super();
}
async run(): Promise<void> {
return this.usecases.getModels().then(console.table);
return this.usecases
.getModels()
.then(console.table)
.then(() => this.usecases.isAPIServerOnline())
.then((isOnline) => {
if (isOnline) console.log('API server is online');
});
}
}
40 changes: 37 additions & 3 deletions cortex-js/src/infrastructure/commanders/serve.command.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { spawn } from 'child_process';
import {
CORTEX_JS_STOP_API_SERVER_URL,
defaultCortexJsHost,
defaultCortexJsPort,
} from '@/infrastructure/constants/cortex';
Expand All @@ -9,6 +10,7 @@ import { join } from 'path';
type ServeOptions = {
host?: string;
port?: number;
attach: boolean;
};

@SubCommand({
Expand All @@ -20,7 +22,25 @@ export class ServeCommand extends CommandRunner {
const host = options?.host || defaultCortexJsHost;
const port = options?.port || defaultCortexJsPort;

spawn(
if (_input[0] === 'stop') {
return this.stopServer().then(() => console.log('API server stopped'));
} else {
return this.startServer(host, port, options);
}
}

private async stopServer() {
return fetch(CORTEX_JS_STOP_API_SERVER_URL(), {
method: 'DELETE',
}).catch(() => {});
}

private async startServer(
host: string,
port: number,
options: ServeOptions = { attach: true },
) {
const serveProcess = spawn(
'node',
process.env.TEST
? [join(__dirname, '../../../dist/src/main.js')]
Expand All @@ -32,10 +52,14 @@ export class ServeCommand extends CommandRunner {
CORTEX_JS_PORT: port.toString(),
NODE_ENV: 'production',
},
stdio: 'inherit',
detached: false,
stdio: options?.attach ? 'inherit' : 'ignore',
detached: true,
},
);
if (!options?.attach) {
serveProcess.unref();
console.log('Started server at http://%s:%d', host, port);
}
}

@Option({
Expand All @@ -53,4 +77,14 @@ export class ServeCommand extends CommandRunner {
parsePort(value: string) {
return parseInt(value, 10);
}

@Option({
flags: '-a, --attach',
description: 'Attach to interactive chat session',
defaultValue: false,
name: 'attach',
})
parseAttach() {
return true;
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { HttpStatus, Injectable } from '@nestjs/common';
import {
CORTEX_CPP_MODELS_URL,
CORTEX_JS_HEALTH_URL,
defaultCortexCppHost,
defaultCortexCppPort,
defaultCortexJsHost,
defaultCortexJsPort,
} from '@/infrastructure/constants/cortex';
import { HttpService } from '@nestjs/axios';
import { firstValueFrom } from 'rxjs';
Expand Down Expand Up @@ -56,6 +59,23 @@ export class PSCliUsecases {
).catch(() => []);
}

/**
* Check if the Cortex API server is online
* @param host Cortex host address
* @param port Cortex port address
* @returns
*/
async isAPIServerOnline(
host: string = defaultCortexJsHost,
port: number = defaultCortexJsPort,
): Promise<boolean> {
return firstValueFrom(
this.httpService.get(CORTEX_JS_HEALTH_URL(host, port)),
)
.then((res) => res.status === HttpStatus.OK)
.catch(() => false);
}

private formatDuration(milliseconds: number): string {
const days = Math.floor(milliseconds / (1000 * 60 * 60 * 24));
const hours = Math.floor(
Expand Down
10 changes: 10 additions & 0 deletions cortex-js/src/infrastructure/constants/cortex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@ export const CORTEX_CPP_MODELS_URL = (
port: number = defaultCortexCppPort,
) => `http://${host}:${port}/inferences/server/models`;

export const CORTEX_JS_HEALTH_URL = (
host: string = defaultCortexJsHost,
port: number = defaultCortexJsPort,
) => `http://${host}:${port}/health`;

export const CORTEX_JS_STOP_API_SERVER_URL = (
host: string = defaultCortexJsHost,
port: number = defaultCortexJsPort,
) => `http://${host}:${port}/process`;

// INITIALIZATION
export const CORTEX_RELEASES_URL =
'https://api.github.com/repos/janhq/cortex/releases';
Expand Down
17 changes: 17 additions & 0 deletions cortex-js/src/infrastructure/controllers/process.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Controller, Delete } from '@nestjs/common';
import { ApiOperation, ApiTags } from '@nestjs/swagger';

@ApiTags('Processes')
@Controller('process')
export class ProcessController {
constructor() {}

@ApiOperation({
summary: 'Terminate service',
description: 'Terminate service endpoint',
})
@Delete()
async delete() {
process.exit(0);
}
}
22 changes: 22 additions & 0 deletions cortex-js/src/infrastructure/controllers/status.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Controller, HttpCode, Get } from '@nestjs/common';
import { ApiOperation, ApiTags, ApiResponse } from '@nestjs/swagger';

@ApiTags('Status')
@Controller('health')
export class StatusController {
constructor() {}

@ApiOperation({
summary: 'Health check',
description: 'Health check endpoint.',
})
@HttpCode(200)
@ApiResponse({
status: 200,
description: 'Ok',
})
@Get()
async get() {
return 'OK';
}
}
2 changes: 1 addition & 1 deletion cortex-js/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ async function bootstrap() {
const port = process.env.CORTEX_JS_PORT || defaultCortexJsPort;

await app.listen(port, host);
console.log(`Server running on http://${host}:${port}`);
console.log(`Started server at http://${host}:${port}`);
}

const buildSwagger = (app: INestApplication<any>) => {
Expand Down
3 changes: 1 addition & 2 deletions cortex-js/src/usecases/assistants/assistants.module.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { Module } from '@nestjs/common';
import { AssistantsController } from '@/infrastructure/controllers/assistants.controller';
import { AssistantsUsecases } from './assistants.usecases';
import { DatabaseModule } from '@/infrastructure/database/database.module';

@Module({
imports: [DatabaseModule],
controllers: [AssistantsController],
controllers: [],
providers: [AssistantsUsecases],
exports: [AssistantsUsecases],
})
Expand Down
4 changes: 1 addition & 3 deletions cortex-js/src/usecases/chat/chat.module.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import { Module } from '@nestjs/common';
import { ChatController } from '@/infrastructure/controllers/chat.controller';
import { ChatUsecases } from './chat.usecases';
import { DatabaseModule } from '@/infrastructure/database/database.module';
import { ExtensionModule } from '@/infrastructure/repositories/extensions/extension.module';
import { ModelRepositoryModule } from '@/infrastructure/repositories/models/model.module';
import { HttpModule } from '@nestjs/axios';
import { EmbeddingsController } from '@/infrastructure/controllers/embeddings.controller';

@Module({
imports: [DatabaseModule, ExtensionModule, ModelRepositoryModule, HttpModule],
controllers: [ChatController, EmbeddingsController],
controllers: [],
providers: [ChatUsecases],
exports: [ChatUsecases],
})
Expand Down
3 changes: 1 addition & 2 deletions cortex-js/src/usecases/models/models.module.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Module } from '@nestjs/common';
import { ModelsUsecases } from './models.usecases';
import { ModelsController } from '@/infrastructure/controllers/models.controller';
import { DatabaseModule } from '@/infrastructure/database/database.module';
import { CortexModule } from '@/usecases/cortex/cortex.module';
import { ExtensionModule } from '@/infrastructure/repositories/extensions/extension.module';
Expand All @@ -19,7 +18,7 @@ import { DownloadManagerModule } from '@/download-manager/download-manager.modul
ModelRepositoryModule,
DownloadManagerModule,
],
controllers: [ModelsController],
controllers: [],
providers: [ModelsUsecases],
exports: [ModelsUsecases],
})
Expand Down
3 changes: 1 addition & 2 deletions cortex-js/src/usecases/threads/threads.module.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { Module } from '@nestjs/common';
import { ThreadsUsecases } from './threads.usecases';
import { ThreadsController } from '@/infrastructure/controllers/threads.controller';
import { DatabaseModule } from '@/infrastructure/database/database.module';

@Module({
imports: [DatabaseModule],
controllers: [ThreadsController],
controllers: [],
providers: [ThreadsUsecases],
exports: [ThreadsUsecases],
})
Expand Down

0 comments on commit eed17d3

Please sign in to comment.