跳至主要内容

数据库事件

结构

数据库更改事件的结构取决于模型和执行的操作类型。您可以在 API 参考 中了解更多信息。

以下示例基于此 User 模型

model User {
id Int @id @default(autoincrement())
name String?
email String @unique
}

所有事件都具有以下公共字段

  • id: 唯一标识符
  • modelName: 执行此操作的模型,例如 UserPost
  • action: 执行的事件类型,以下任一:createupdatedelete

根据事件类型,通过 Prisma Pulse 收到的事件对象中可能存在其他字段。请参见以下部分以了解一些示例事件。

创建事件

以下是一个示例事件对象,您可能会在创建新记录时收到该对象

{
action: 'create',
created: { id: 3, email: '[email protected]', name: 'Jane Doe' },
id: '0/2A5A590',
modelName: 'User'
}

更新事件

以下是一个示例事件对象,您可能会在更新记录时收到该对象

{
action: 'update',
after: { id: 2, email: '[email protected]', name: 'Jane Doe' },
before: null,
id: '0/2A5A248',
modelName: 'User'
}

如果希望 before 字段包含记录在更新之前的值,则需要将 REPLICA IDENTITY 设置为 FULL,如 此处 所述。在这种情况下,事件对象可能如下所示

{
action: 'update',
after: { id: 2, email: '[email protected]', name: 'Jane Doe' },
before: { id: 2, email: '[email protected]', name: 'Jane' },
id: '0/2A5A248',
modelName: 'User'
}

删除事件

以下是一个示例事件对象,您可能会在删除记录时收到该对象

 {
action: 'delete',
deleted: { id: 1 },
id: '0/2A5A398',
modelName: 'User'
}

如果希望 deleted 字段包含已删除记录的值,则需要将 REPLICA IDENTITY 设置为 FULL,如 此处 所述。否则,它只会包含记录的 id 值。在这种情况下,事件对象可能如下所示

 {
action: 'delete',
deleted: { id: 21, email: '[email protected]', name: 'Jane Doe' },
id: '0/2A5A398',
modelName: 'User'
}

交付语义

本节概述了 Prisma Pulse 的事件交付语义。

什么是事件交付语义?

事件交付语义描述了事件生产者可以在事件驱动架构中提供的有关事件交付的保证

通常有三种类型的交付保证

  • 最多一次:事件要么交付一次,要么根本不交付。
  • 至少一次:事件交付一次或多次,确保它永远不会未交付。
  • 恰好一次:事件恰好交付一次,避免重复。

Prisma Pulse 中的事件交付语义

以下是 Prisma Pulse 中的事件交付语义摘要

stream()subscribe()
需要事件持久性
交付保证至少一次最多一次
事件顺序与生产事件的顺序相同可能与生产事件的顺序不同
可以“重播”错过的事件
警告

请注意,如果事件超过了您订阅计划大小限制,则该事件将被拒绝,并且不会传递到您的应用程序。

stream()

使用 stream() 时,Prisma Pulse 提供以下交付保证

至少一次交付

使用 stream() 流式传输数据库更改事件时,保证数据库更改事件使用至少一次语义交付,这意味着 Prisma Pulse 可以保证发生的任何数据库事件都会交付一次或多次。

按正确顺序交付事件

Prisma Pulse 进一步保证按生产顺序交付数据库更改事件。

恰好一次交付

虽然 Pulse 默认提供至少一次语义,但它也提供基元,供您自己实现恰好一次交付保证!

Prisma Pulse 生成的每个事件都包含一个标识符/幂等键,您可以使用它在事件的下游处理过程中进行重复数据删除。最好通过将标识符传递到支持幂等的外部服务或在使用数据库时使用类似更新的概念来实现这一点。

此事件有效负载中针对 User 模型的 id 字段表示标识符/幂等键

{
action: 'update',
after: { id: 1, name: 'Jane', email: "[email protected]" },
before: null,
id: '01HYBEER1JPSBVPG2NQADNQTA6',
modelName: 'User'
}

subscribe()

最多一次交付

使用 .subscribe() 流式传输数据库更改事件时,保证数据库更改事件使用最多一次语义交付,这意味着某些数据库事件可能会丢失。

不保证事件顺序

subscribe() 不保证事件到达的顺序。

事件持久性

您可以在控制台 项目 中为 Pulse 配置事件持久性。只有在启用事件持久性的情况下,您才能通过 stream() API 利用 Prisma Pulse 的至少一次正确顺序交付保证。

哪些事件被持久化?

在您为控制台 项目 中的 Pulse 启用事件持久性后,Pulse 将存储来自所有表所有数据库事件。

事件以什么形式持久化?

事件以与交付时相同的 结构 持久化。

事件持久性如何影响定价?

启用事件持久性后,定价将受到以下影响

  • 数据库事件:Pulse 捕获的数据库事件数
  • 事件读取:Pulse 通过 .stream() 读取交付的数据库事件数
  • 事件存储:存储的事件消耗的磁盘空间量(以 GiB 为单位)

有关详细信息,请参见 订阅计划。定价适用于您使用 subscribe()stream()

恢复事件流

stream() API 提供了提供 name 参数的选项,这使得流成为可恢复的

const stream = await prisma.user.stream({
name: "all-user-events"
})

如果提供了 name,Pulse 将使用游标跟踪事件的交付。只有在接收方确认事件时,与该 name 关联的游标才会移动。

如果流由于某种原因不可用,例如您的服务器已关闭,接收方将无法确认任何事件。流再次可用后,流将从最后一个游标位置继续,并交付在此期间尚未确认的任何事件

Resuming event streams with a name argument

如果省略了 name 选项,则不会将游标与流关联,并且流关闭期间发生的事件将不会被交付

Resuming event streams without a name argument

请注意,如果提供了 name,则在任何给定时间只能有一个客户端连接到具有该特定 name 的流。