如何在NestJS中重新初始化EdgeDB数据库提供者以应用更新配置?
解决NestJS+EdgeDB全局变量不生效的问题
核心问题分析
- EdgeDB客户端不可变性:
withGlobals()返回新的客户端实例,而非修改原实例,若未替换服务中的client引用,后续查询仍使用旧实例。 - 单例作用域冲突:NestJS默认单例服务全局共享,存储请求级别的
current_user_id会导致并发请求互相覆盖。 - 异步调用未等待:若调用
setGlobals时未加await,后续操作会在实例更新完成前执行,导致全局变量未生效。
解决方案
1. 修改EdgeDBService为请求作用域
将服务改为请求级作用域,每个请求生成独立的服务实例,彻底隔离请求上下文:
import { Injectable, Scope, OnModuleInit } from '@nestjs/common'; import * as edgedb from 'edgedb'; import type { EdgeQLTypes } from 'edgedb'; @Injectable({ scope: Scope.REQUEST }) // 关键:设置请求作用域 export class EdgeDBService implements OnModuleInit { client: edgedb.Client; constructor() { this.client = edgedb.createClient(); } async onModuleInit() { await this.client.ensureConnected(); } public async setGlobals(globals: { current_user_id: string }) { // 替换为带全局变量的新客户端实例 this.client = this.client.withGlobals(globals); console.log(await this.client.query(`select global current_user_id;`)); } public async query<Expr extends EdgeQLTypes.Expression>(expression: Expr): Promise<EdgeQLTypes.$infer<Expr>> { return expression.run(this.client); } }
2. 确保异步调用等待完成
调用setGlobals时必须加await,保证客户端实例更新后再执行查询:
// 示例控制器代码 import { Controller, Get, Req } from '@nestjs/common'; import { EdgeDBService } from './edgedb.service'; import { PetsService } from './pets.service'; @Controller('pets') export class PetsController { constructor( private readonly edgedb: EdgeDBService, private readonly petsService: PetsService ) {} @Get() async getPets(@Req() req) { // 等待全局变量设置完成 await this.edgedb.setGlobals({ current_user_id: req.user.id }); return this.petsService.getPets(); } }
3. 优化PetsService的查询逻辑
统一使用EdgeDBService提供的query方法,避免直接访问client属性,确保使用最新的客户端实例:
import { Injectable } from '@nestjs/common'; import * as e from '../dbschema/edgeql-js'; import { EdgeDBService } from './edgedb.service'; @Injectable() export class PetsService { constructor(private readonly edgedb: EdgeDBService) {} async getPets() { // 使用query方法获取全局变量,确保用最新实例 const currentUserId = await this.edgedb.query(e.select(e.global.current_user_id)); console.log(currentUserId); return this.edgedb.query( e.select(e.Pets, (item) => ({ ...e.Pets['*'], })) ); } }
关键说明
- 请求作用域的服务会为每个HTTP请求创建新实例,完全避免并发请求间的全局变量冲突。
- EdgeDB的
withGlobals()是不可变操作,必须替换服务中的client引用才能让后续查询生效。 - 所有异步操作必须等待完成,否则会出现实例未更新的情况。
内容的提问来源于stack exchange,提问作者Pa Ye
相关产品推荐
相关产品推荐

