TL;DR

不要打印 PrismaClient 对象。


纪念一下因为这件事失去的一天。

发现的过程

起因是咱在 Nuxt 里用 middleware 往 event.context 里塞了一个 PrismaClient,然后在另一个地方又不小心打印了一下 event。导致只要请求发过来,到了打印的位置就直接卡死,刷新页面提示「Reloading server」。

刚开始在怀疑是不是 Nuxt 的某个 bug,后来建立了好几个空项目测试,一次卡死的情况都没有出现。于是又怀疑是不是自己在连接 PrismaClient 的时候写了什么问题,但对着那七八行初始化数据库的代码进行了手动测试之后发现自己被骗了——跟这里一点关系都没有。如果把整个 middleware 删掉还是能恢复正常的,但数据库连接的任何一行都没有问题。

然后咱又建立了一个新的项目,把原项目的代码复制了过去,发现可以复现这个问题,于是开始缩减代码,删了一部分之后发现又正常了。于是一脸懵逼地对着原项目改,把原项目一行行改成正常的副本的样子,每改一行就重启一下(因为那行代码导致整个 Node.js 卡死了,所以 Nuxt 的热重载自然也没用了,只能强制结束并重启)看看是不是正常。当改到其中一行打印语句的时候,突然发现功能就正常了!

想起来之前把整个 middleware 都删掉就恢复正常了,咱猜测是这里跟 middleware 重叠的部分导致了这个问题,那么真相就只有一个了——

1
2
3
4
export default defineEventHandler((event) => {
console.log(event.context.prisma)
return 'Hello World!'
})

尝试了一下上面的最简 eventHandler,然后请求这个接口,果然 Node.js 卡死了…

然后咱又建立了一个完全新的 Prisma 项目,想知道到底是 Nuxt + Prisma 才会出现这种情况还是 Prisma 自身就会出现。

1
2
3
4
import { PrismaClient } from '@prisma/client'

const client = new PrismaClient()
console.log(client)

上面就是复现的所有代码,运行之后果然卡住了,等待半分钟左右控制台开始打印彩色文字,由此大概可以推断是这个 PrismaClient 里有大量可序列化的数据,打印导致 Node.js 的资源全部花在序列化这个对象上了。而在 Nuxt 里,可能是又包了一层框架的原因,导致卡的时间更加长。

不过还有一个猜想就是序列化这个对象就卡住是不是因为底层在对数据库进行查询,于是弄了个 SQLite 的数据库给 PrismaClient 连接,然后运行上面的复现代码,发现磁盘没有什么明显变化,倒是 CPU 和内存占用在稳步上升,好吧…看来这个猜想是错的。

总之,在任何情况下都不要打印这个玩意就对了。