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:
lborv
2025-10-09 19:54:08 +03:00
parent c3189bb2df
commit 174dbbcdba
9 changed files with 97 additions and 12 deletions

View File

@ -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[];
}

View File

@ -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],

View File

@ -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 {