feat: integrate RedisNode management into Project and Query services; enhance RedisNodeService with optimal node selection and connection options; update vm.constants to include RedisPlugin
This commit is contained in:
@ -27,11 +27,9 @@ export class DatabaseNodeService extends DatabaseEncryptionService {
|
||||
return null;
|
||||
}
|
||||
|
||||
return nodes.reduce((optimalNode, currentNode) => {
|
||||
const currentCount = currentNode.databases?.length || 0;
|
||||
const optimalCount = optimalNode.databases?.length || 0;
|
||||
return currentCount < optimalCount ? currentNode : optimalNode;
|
||||
});
|
||||
nodes.sort((a, b) => a.databases.length - b.databases.length);
|
||||
|
||||
return nodes[0];
|
||||
}
|
||||
|
||||
async initDatabase(
|
||||
|
||||
@ -4,12 +4,14 @@ import {
|
||||
Column,
|
||||
Entity,
|
||||
JoinColumn,
|
||||
ManyToMany,
|
||||
OneToMany,
|
||||
OneToOne,
|
||||
PrimaryGeneratedColumn,
|
||||
} from "typeorm";
|
||||
import { Database } from "../../databaseManager/entities/database.entity";
|
||||
import { FunctionEntity } from "../../query/entities/function.entity";
|
||||
import { RedisNode } from "../../redisManager/entities/redis.node.entity";
|
||||
|
||||
@Entity("project")
|
||||
export class Project {
|
||||
@ -31,4 +33,8 @@ export class Project {
|
||||
|
||||
@OneToMany(() => FunctionEntity, (functionEntity) => functionEntity.project)
|
||||
functions: FunctionEntity[];
|
||||
|
||||
@ManyToMany(() => RedisNode, (redisNode) => redisNode.projects)
|
||||
@JoinColumn()
|
||||
redisNodes: RedisNode[];
|
||||
}
|
||||
|
||||
@ -24,4 +24,10 @@ export class ProjectService {
|
||||
database: { id: databaseId },
|
||||
});
|
||||
}
|
||||
|
||||
updateRedisNode(projectId: string, redisNodeId: { id: string }[]) {
|
||||
return this.projectRepository.update(projectId, {
|
||||
redisNodes: redisNodeId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { RedisNodeService } from "./../../redisManager/redisNode/redis.node.service";
|
||||
import { Inject, Injectable } from "@nestjs/common";
|
||||
import { InjectRepository } from "@nestjs/typeorm";
|
||||
import { Query } from "../entities/query.entity";
|
||||
@ -25,6 +26,7 @@ export class QueryExecuterService {
|
||||
@Inject(FunctionService)
|
||||
private readonly functionService: FunctionService,
|
||||
readonly databaseManagerService: DatabaseManagerService,
|
||||
readonly redisNodeService: RedisNodeService,
|
||||
@InjectQueue(QUEUE_NAMES.QUERY) private queryQueue: Queue
|
||||
) {
|
||||
this.queueEvents = new QueueEvents(this.queryQueue.name);
|
||||
|
||||
@ -12,6 +12,7 @@ import { QueueModule } from "src/queue/queue.module";
|
||||
import { FunctionEntity } from "./entities/function.entity";
|
||||
import { FunctionService } from "src/project/function/function.service";
|
||||
import { FunctionController } from "src/project/function/function.controller";
|
||||
import { RedisManagerModule } from "src/redisManager/redisManager.module";
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@ -19,6 +20,7 @@ import { FunctionController } from "src/project/function/function.controller";
|
||||
forwardRef(() => DatabaseManagerModule),
|
||||
forwardRef(() => ApiModule),
|
||||
forwardRef(() => QueueModule),
|
||||
forwardRef(() => RedisManagerModule),
|
||||
TypeOrmModule.forFeature([Query, FunctionEntity]),
|
||||
],
|
||||
controllers: [QueryController, CommandController, FunctionController],
|
||||
|
||||
@ -1,4 +1,11 @@
|
||||
import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";
|
||||
import { Project } from "../../project/entities/project.entity";
|
||||
import {
|
||||
Column,
|
||||
Entity,
|
||||
JoinColumn,
|
||||
ManyToMany,
|
||||
PrimaryGeneratedColumn,
|
||||
} from "typeorm";
|
||||
|
||||
@Entity("redisNode")
|
||||
export class RedisNode {
|
||||
@ -16,4 +23,8 @@ export class RedisNode {
|
||||
|
||||
@Column({ type: "varchar", length: 255 })
|
||||
password: string | null;
|
||||
|
||||
@ManyToMany(() => Project, (project) => project.redisNodes)
|
||||
@JoinColumn()
|
||||
projects: Project[];
|
||||
}
|
||||
|
||||
@ -4,9 +4,14 @@ import { RedisNode } from "./entities/redis.node.entity";
|
||||
import { RedisManagerController } from "./redis.manager.controller";
|
||||
import { RedisNodeService } from "./redisNode/redis.node.service";
|
||||
import { ApiModule } from "src/api/api.module";
|
||||
import { ProjectModule } from "src/project/project.module";
|
||||
|
||||
@Module({
|
||||
imports: [forwardRef(() => ApiModule), TypeOrmModule.forFeature([RedisNode])],
|
||||
imports: [
|
||||
forwardRef(() => ApiModule),
|
||||
forwardRef(() => ProjectModule),
|
||||
TypeOrmModule.forFeature([RedisNode]),
|
||||
],
|
||||
controllers: [RedisManagerController],
|
||||
providers: [RedisNodeService],
|
||||
exports: [RedisNodeService],
|
||||
|
||||
@ -1,13 +1,16 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { Inject, Injectable } from "@nestjs/common";
|
||||
import { InjectRepository } from "@nestjs/typeorm";
|
||||
import { RedisNode } from "../entities/redis.node.entity";
|
||||
import { Repository } from "typeorm";
|
||||
import { ProjectService } from "src/project/project.service";
|
||||
|
||||
@Injectable()
|
||||
export class RedisNodeService {
|
||||
constructor(
|
||||
@InjectRepository(RedisNode)
|
||||
private readonly redisNodeRepository: Repository<RedisNode>
|
||||
private readonly redisNodeRepository: Repository<RedisNode>,
|
||||
@Inject(ProjectService)
|
||||
private readonly projectService: ProjectService
|
||||
) {}
|
||||
|
||||
async create(
|
||||
@ -36,15 +39,55 @@ export class RedisNodeService {
|
||||
return this.redisNodeRepository.save(redisNode);
|
||||
}
|
||||
|
||||
async getConnectionOptions(id: string): Promise<{
|
||||
async findOptimalNode(): Promise<RedisNode | null> {
|
||||
const nodes = await this.redisNodeRepository.find({
|
||||
relations: ["projects"],
|
||||
});
|
||||
|
||||
if (nodes.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
nodes.sort((a, b) => a.projects.length - b.projects.length);
|
||||
|
||||
return nodes[0];
|
||||
}
|
||||
|
||||
async getConnectionOptions(projectId: string): Promise<{
|
||||
host: string;
|
||||
port: number;
|
||||
username: string;
|
||||
password: string;
|
||||
}> {
|
||||
const node = await this.redisNodeRepository.findOne({ where: { id } });
|
||||
const project = await this.projectService.findById(projectId);
|
||||
|
||||
if (!project) {
|
||||
throw new Error("Project not found");
|
||||
}
|
||||
|
||||
const node = project.redisNodes[0];
|
||||
if (!node) {
|
||||
throw new Error("Redis node not found");
|
||||
const newNode = await this.findOptimalNode();
|
||||
|
||||
if (!newNode) {
|
||||
throw new Error("No Redis nodes available");
|
||||
}
|
||||
|
||||
project.redisNodes.push(newNode);
|
||||
newNode.projects.push(project);
|
||||
await this.redisNodeRepository.save(newNode);
|
||||
|
||||
await this.projectService.updateRedisNode(
|
||||
project.id,
|
||||
project.redisNodes.map((n) => ({ id: n.id }))
|
||||
);
|
||||
|
||||
return {
|
||||
host: newNode.host,
|
||||
port: newNode.port,
|
||||
username: newNode.user,
|
||||
password: newNode.password,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@ -3,6 +3,7 @@ import { DatabasePlugin } from "./plugins/database.plugin";
|
||||
import { Query } from "src/query/entities/query.entity";
|
||||
import { QueryPlugin } from "./plugins/query.plugin";
|
||||
import { AxiosPlugin } from "./plugins/axios.plugin";
|
||||
import { RedisPlugin } from "./plugins/redis.plugin";
|
||||
|
||||
export const registeredPlugins = {
|
||||
db: async (service: QueryExecuterService, query: Query) => {
|
||||
@ -18,6 +19,17 @@ export const registeredPlugins = {
|
||||
|
||||
return DatabasePlugin.init("db", databaseConnection);
|
||||
},
|
||||
redis: async (service: QueryExecuterService, query: Query) => {
|
||||
const redisConnection = await service.redisNodeService.getConnectionOptions(
|
||||
query.project.id
|
||||
);
|
||||
|
||||
if (!redisConnection) {
|
||||
throw new Error("Redis connection not found");
|
||||
}
|
||||
|
||||
return RedisPlugin.init("redis", redisConnection, query.project.id);
|
||||
},
|
||||
axios: async () => {
|
||||
return AxiosPlugin.init("axios");
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user