[RFC] 036 - LobeChat 服务端数据库 & ORM #1851
Replies: 8 comments 13 replies
This comment has been hidden.
This comment has been hidden.
-
试了下 Opus 似乎可以: |
Beta Was this translation helpful? Give feedback.
-
DB 接入实现思路由于之前在 #378 完成了 client 端 DB 的改造,使之非常接近关系型数据库的结构。所以到今天这个节点来实现服务端数据库存储时,收益非常大。经过 #2038 这个 PR 的梳理,目前看下来只需要实现 6 个 services 的 server 端调用逻辑,即可完成服务端数据库方案的基础功能。像 store 那一层可以完全不用改。 不过由于目前 client 和 server 的 db 不是同一套,后续难免需要维护两套实现逻辑。所以在这次实现过程中,需要尽量统一并减少 service 层的接口数量,能复用尽量复用已有的方法。 此外,由于之前在 client DB 下并没有 user 层面的鉴权+ 查询逻辑,因此这部分逻辑应该是存在一定的改造量,可能需要和 #2022 一起考虑。 最后,虽说 store 那一层不改也能完成所有主链路,但是由于 sever 调用相比 client 要耗时很多,也存在各种请求出错的情况。因此也需要完善相应的错误处理的逻辑。 tRPC 接入由于上述方案只需要改造 6个 service 的调用,肯定是尽可能希望类型统一,这样的话采用 tRPC 的方案应该是最为合适的。相当于是在 client 的 db 中使用直接使用 这样一来,两种不同模式的数据调用链路就是:
进展 |
Beta Was this translation helpful? Give feedback.
-
tRPC高层次介绍 tRPCtRPC 是一个为全栈 TypeScript 开发者设计的框架,它简化了前后端安全使用端点的过程。tRPC 允许你在客户端和服务器之间实现类型安全的通信,而不需要声明额外的类型,因为它从你的 TypeScript 代码中推断出类型信息。这种方法提供了与 REST 或 GraphQL 相比的一种类型安全的替代方案,特别是在使用 TypeScript 的项目中。 tRPC 的设计理念是基于插件化的,它支持高性能操作并且可以与多种现代 JavaScript 框架(如 Next.js 或 Remix)无缝集成。这使得 tRPC 在构建快速且类型安全的应用程序时显得非常有效。 最小启动用例要在项目中启动 tRPC,你需要设置一个基本的 tRPC 应用程序,包括服务器和客户端配置。下面是一个最小的启动用例:
这个最小示例展示了如何设置一个简单的 tRPC 应用程序,包括服务器和客户端配置。通过这种方式,你可以在项目中快速地集成 tRPC,并开始构建类型安全的全栈应用程序。 什么是
|
Beta Was this translation helpful? Give feedback.
-
这一层记录一些实践经验与笔记 |
Beta Was this translation helpful? Give feedback.
-
DB PR 剩余相关改造: User Store
Agent Store
数据结构迁移
Topic 数据优化
File 上传乐观更新
数据导入重构
|
Beta Was this translation helpful? Give feedback.
-
DB Schema 在版本升级过程中无感 migration类似于前端 db ,我们需要一个服务端db无感升级的方案,这样可以确保在版本自动发布过程中,用户的 db schema 会自动升级到最新版 实现思路: Drizzle ORM 提供了程序化迁移的方法,使用该方法,在每次 vercel build 之后,执行一次迁移。如果能正常通过,说明迁移成功,否则 db 的升级失败。 import * as dotenv from 'dotenv';
import * as migrator from 'drizzle-orm/neon-serverless/migrator';
import { join } from 'node:path';
import { serverDB } from '../../src/database/server/core/db';
// Read the `.env` file if it exists, or a file specified by the
// dotenv_config_path parameter that's passed to Node.js
dotenv.config();
const runMigrations = async () => {
await migrator.migrate(serverDB, {
migrationsFolder: join(__dirname, '../../src/database/server/migrations'),
});
console.log('✅ database migration pass.');
// eslint-disable-next-line unicorn/no-process-exit
process.exit(0);
};
let connectionString = process.env.DATABASE_URL;
// only migrate database if the connection string is available
if (connectionString) {
// eslint-disable-next-line unicorn/prefer-top-level-await
runMigrations().catch((err) => {
console.error('❌ Database migrate failed:', err);
// eslint-disable-next-line unicorn/no-process-exit
process.exit(1);
});
} 目前已经在线上实际测试,运行良好。 |
Beta Was this translation helpful? Give feedback.
-
Github Action 集成数据库测试
export default defineConfig({
// ...
poolOptions: {
threads: { singleThread: true },
},
})
jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env:
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
ports:
- 5432:5432
|
Beta Was this translation helpful? Give feedback.
-
背景
LobeChat 1.0 要接入数据库方案了,需要确定一下后端数据库方案 & ORM 方案。
设计思路
数据库
数据库没啥好说的,已经确定用 PostgresSQL 了,这个好处很明显:
DATABASE_URL
就可以用;ORM
针对 ORM 部分,之前比较确定的是采用了 Prisma:prisma.io 。不过最近又研究了下 Drizzle ORM ,说实话也是有点心动的。
Prisma 其实存在几个问题:
Drizzle ORM 的话比起 prisma 的优势在于:
prisma generate
那一套,直接就是 TS schema;但是它存在一个核心的缺陷: AI 不友好:
如果其他模型也不缺少 Dirzzle ORM 的语料,那么直接拿这个用上生产就会比较难。所以最近我可能会试试看其他模型是否能懂 Drizzle 的使用。
client 与 server 的统一
另外最近看到的另外一个比较远的消息,drizzle 支持了 PGLite :https://github.com/drizzle-team/drizzle-orm/releases/tag/0.30.6 ,PGLite 是 Postgres 的本地 wasm 版本。因此如果采用 drizzle 的话,我们后续有可能可以统一 client 和 server 侧的数据库选型都到 Postgres 上,然后通过 electric 这样的方案实现 client 与 server 的实时同步,这对于长期迭代来看可能是一个比较好的模式,可以统一成一个 ORM 维护。
进展
基础代码改造
Client 与 Server 区分
store 异步化适配
乐观更新 & loading 适配
数据结构改造
关键 PR
Beta Was this translation helpful? Give feedback.
All reactions