资讯动态

Prisma 服务端订阅(Server-side Subscriptions)实战:用 Webhook 把数据库变更推送给 Serverless 应用

发布时间:2026/9/23 2:39:52 来源:尧图企业网站定制
后端数据库GraphQL【免费下载链接】prisma1 Database Tools incl. ORM, Migrations and Admin UI (Postgres, MySQL MongoDB) [deprecated]项目地址https://gitcode.com/gh_mirrors/pr/prisma1点击查看免费下载导读本文讲解 Prisma当前仓库 prisma1即 deprecated 的 Prisma 1.x 开源版本中的**服务端订阅Server-side Subscriptions**机制它拥有与普通 GraphQL Subscriptions 等价的过滤能力但事件不是通过 WebSocket 推送给订阅客户端而是由 Prisma 服务端在数据变更时执行订阅查询并把查询结果以Webhook的形式通过 HTTP 推送到你指定的 URL。读完本文你将掌握在prisma.yml中配置服务端订阅的完整写法含内联 query、.graphql文件、自定义 headers 等变体理解其触发与投递的底层执行链路并能从源码与集成测试层面验证其行为边界。服务端订阅与 GraphQL 订阅等价、交付方式不同能力等价同样的过滤 API原文档明确指出服务端订阅在能力上与普通 GraphQL 订阅完全等价。这意味着你可以使用与客户端 GraphQL 订阅完全相同的过滤语法例如mutation_in: [CREATED, UPDATED, DELETED]只在感兴趣的事件类型上收到通知node内层过滤对变更节点的字段值进行约束previousValues读取变更前的旧值。Prisma 会持续监控数据变更当一次 mutation 发生且满足订阅查询中的过滤条件时就执行该订阅查询——这与普通 GraphQL 订阅的触发逻辑一致区别仅在于结果如何送达对比维度普通 GraphQL 订阅服务端订阅Server-side Subscriptions过滤 API相同where等参数相同触发时机数据变更时由 Prisma 监控并执行查询数据变更时由 Prisma 监控并执行查询交付方式通过 WebSocket 推送给在线订阅客户端通过 HTTP Webhook 投递到配置的 URL目标场景浏览器 / 实时前端无状态的后端服务、Serverless 函数为 Serverless 而生服务端订阅的设计初衷是与现代的Serverless 基础设施协同工作Serverless 函数如 AWS Lambda是无状态的、无法维持长连接因此基于 WebSocket 的订阅模型并不适合直接对接。Webhook 模型让 Prisma 可以在事件发生时发起一次普通的 HTTP 请求Serverless 函数只需要暴露一个 HTTP 端点即可接收事件。从本仓库的实现看当前版本支持通过webhook交付事件文档同时预告了未来会加入对 AWS Lambda 直接调用以及不同消息队列实现的支持当前以 webhook 为主要交付通道相关队列基础设施可参见 PrismaLocalDependencies.scala 与 PrismaProdDependencies.scala 中的webhookPublisher/webhooksConsumer定义。配置服务端订阅prisma.yml 中的 subscriptions 属性服务端订阅的配置入口是服务根目录下的prisma.yml文件通过subscriptions属性声明。该属性在prisma.yml的 YAML 结构文档 中被明确定义为**可选optional**对象每个订阅至少需要两部分信息订阅查询subscription query定义在何种事件上触发函数、以及回调负载payload长什么样webhook 的 URL事件发生时通过 HTTP 调用的地址可选若干 HTTP headers附加到发送到该 URL 的请求上。完整配置示例原文档以下配置声明了一个名为userChangedEmail的服务端订阅当任意user节点发生UPDATED变更时Prisma 执行订阅查询并把查询结果 POST 到http://example.org/sendSlackMessage同时携带Content-Type与Authorization两个请求头endpoint: ${env:PRISMA_ENDPOINT} secret: ${env:PRISMA_SECRET} datamodel: database/datamodel.graphql subscriptions: userChangedEmail: webhook: url: http://example.org/sendSlackMessage headers: Content-Type: application/json Authorization: Bearer cha2eiheiphesash3shoofo7eceexaequeebuyaequ1reishiujuu6weisao7ohc query: | subscription { user(where: { mutation_in: [UPDATED] }) { node { name email } } }要点解读subscriptions的每个键这里是userChangedEmail是订阅的自定义名称也是投递到 webhook 时标识函数身份的functionNamequery可以像上面这样内联写在prisma.yml中也可以指向一个.graphql文件见下文webhook需要提供url与可选的headersheaders 常用于鉴权如Authorization与告知接收方内容类型。触发示例上面配置的userChangedEmail订阅会在执行如下 mutation 时被触发mutation { updateUser( data: { email: newemail.com }, where: { id: cjcgo976g5twb018740bzyy4q } ) { id } }该 mutation 把 id 为cjcgo976g5twb018740bzyy4q的user的email更新为newemail.com。因为订阅过滤条件mutation_in: [UPDATED]命中了UPDATED类型Prisma 会执行订阅查询webhook 负载中包含node更新后的name与email。subscriptions 属性的完整语法与变体结合 prisma.yml 的 YAML 结构参考subscriptions的完整用法如下类型定义query必填订阅查询的文件路径或内联的 GraphQL 订阅字符串webhook必填要调用的 webhook 信息URL 与可选 headers。如果没有 headers可以直接把 URL 字符串赋给webhook属性如果带 headers则webhook需是一个含url与headers的对象。变体一无 headers直接使用 URL 字符串subscriptions: sendWelcomeEmail: query: database/subscriptions/sendWelcomeEmail.graphql webhook: https://bcdeaxokbj.execute-api.eu-west-1.amazonaws.com/dev/sendWelcomeEmail变体二带多个 headerssubscriptions: sendWelcomeEmail: query: database/subscriptions/sendWelcomeEmail.graphql webhook: url: https://bcdeaxokbj.execute-api.eu-west-1.amazonaws.com/dev/sendWelcomeEmail headers: Authorization: ${env:MY_ENDPOINT_SECRET} Content-Type: application/json变体三与 custom 变量结合subscriptions中的值同样支持 变量引用如${env:...}、${self:custom...}便于复用端点地址与查询目录custom: serverlessEndpoint: https://bcdeaxokbj.execute-api.eu-west-1.amazonaws.com/dev subscriptionQueries: database/subscriptions/ subscriptions: sendWelcomeEmail: query: ${self:custom.subscriptionQueries}/sendWelcomeEmail.graphql webhook: https://${self:custom.serverlessEndpoint}/sendWelcomeEmail源码级剖析从 prisma.yml 到 webhook 投递的完整执行链路1. CLI 侧订阅配置的解析Prisma CLI 在部署时读取prisma.yml并解析订阅定义核心逻辑位于 cli/packages/prisma-yml/src/PrismaDefinition.ts 的getSubscriptions()方法PrismaDefinition.ts 第 318-352 行遍历subscriptions对象的每个键值对兼容webhook的两种写法若webhook是字符串则直接作为 URL若是对象则取.url与.headersheaders 会被transformHeaders归一化处理对query做处理如果query以.graphql结尾则视为相对prisma.yml所在目录的文件路径读取该文件内容作为查询文件不存在会抛出明确错误Subscription query ... provided in subscription ... in prisma.yml does not exist否则视为内联查询字符串最终产出{ name, query, headers, url }的订阅描述供部署使用。2. 服务器侧触发与执行当一次 mutation 在数据库中产生变更后API 服务器会生成副作用 mutactionside-effect mutaction由 SideEffectMutactionExecutor.scala 分派执行第 22-25 行def execute(mutaction: SideEffectMutaction): Future[Unit] mutaction match { case mutaction: PublishSubscriptionEvent PublishSubscriptionEventExecutor.execute(mutaction, apiDependencies.sssEventsPubSub) case mutaction: ExecuteServerSideSubscription ServerSideSubscriptionExecutor.execute(mutaction) }其中ServerSideSubscriptionExecutor.execute第 37-75 行是服务端订阅的核心根据function.delivery的形态判断交付方式WebhookDelivery走 webhook 分支调用SubscriptionExecutor.execute在内存中执行订阅查询注意两个关键参数skipPermissionCheck true服务端订阅的查询不受普通 API 权限检查限制由服务端自动执行alwaysQueryMasterDatabase true始终查询主数据库保证读到最新数据只有当执行结果包含data键即订阅查询有匹配结果时才构造Webhook并发布到webhookPublisher队列url、headers直接来自prisma.yml中的配置payload是订阅查询的 JSON 结果字符串projectId、functionName即prisma.yml中订阅的名字、requestId用于追踪标识若查询结果为空过滤器未匹配则不发布任何 webhook。Webhook的数据结构定义在 server/servers/api/src/main/scala/com/prisma/subscriptions/Webhook.scala包含projectId、functionName、requestId、url、payload、id、headers七个字段。3. 过滤器评估与结果判定server/servers/api/src/main/scala/com/prisma/subscriptions/SubscriptionExecutor.scala 揭示了“订阅是否触发”的判定逻辑第 72-104 行用本次 mutation 的类型、updatedFields、previousValues构建内部订阅 schemaSubscriptionSchema通过QueryTransformer.evaluateInMemoryFilters与VariablesTransformer.evaluateInMemoryFilters先在内存中评估过滤条件如mutation_in、node字段约束只有filtersMatch variablesMatch都成立时才用 Sangria Executor 真正执行转换后的订阅查询执行完毕后在结果中查找与模型名对应的顶层字段如user若该字段值为null例如node: null则整体视为未匹配、不投递 webhook第 127-130 行。测试验证webhook 在各种变更类型下的行为仓库中的集成测试 server/servers/api/src/test/scala/com/prisma/subscriptions/EmbeddedServerSideSubscriptionSpec.scala 通过内存 webhook 队列webhookTestKit完整验证了服务端订阅的行为这些用例可以帮助你理解并预测生产环境中的实际表现场景行为createTodo创建节点命中CREATED订阅发布 1 个 webhookpayload 中node为新建节点数据、previousValues为nullupdateTodo更新节点命中UPDATED订阅发布 1 个 webhookpayload 同时包含更新后的node与previousValues旧值deleteTodo删除节点命中DELETED订阅发布 1 个 webhookpayload 中node为null、previousValues为删除前的值嵌套变更如createTodo内嵌createcomment命中comment订阅同样发布 1 个 webhooknode.comments包含嵌套创建的节点变更不满足过滤条件如status: DONE不匹配node.status: ACTIVE过滤不发布任何 webhook从测试断言还可以看到两个重要事实webhook 的 headers 会原样传递测试配置headers Vector(header - value)最终断言webhook.headers Map(header - value)payload 即为订阅查询的 JSON 结果如更新场景下 payload 形如{data: {todo: {node: {...}, previousValues: {...}}}}与你在订阅查询中声明的字段选择完全一致。部署与使用注意事项webhook 端点必须是可公网访问的 HTTP(S) 地址Prisma 服务器会主动向该地址发起请求本地localhost仅在 Prisma 与接收方同机部署时可用secret 与鉴权推荐在prisma.yml顶层配置secret如secret: ${env:PRISMA_SECRET}保护 API 与订阅配置并通过 webhook 的headers携带接收方所需的鉴权凭证如Authorization: Bearer ...payload 形状与字段选择一致订阅查询中声明的字段决定了 webhook 负载内容如需previousValues必须在查询中显式声明该字段匹配失败不投递订阅查询过滤条件未命中时不会产生 webhook 请求源码层面由filtersMatch/variablesMatch与结果判空共同保证因此不用担心无关变更带来的噪声流量交付通道现状本仓库版本以 webhook 为唯一交付实现WebhookDelivery分支源码中保留了其他交付类型的兜底分支case _ Future.unit为后续扩展 AWS Lambda 直接调用与队列实现预留了位置。参考文档与源码索引本文主体文档docs/1.12/04-Reference/04-Server_side-Subscriptions/01-Overview.mdprisma.yml完整结构与subscriptions属性说明docs/1.12/04-Reference/02-Service-Configuration/02-prisma.yml/02-YAML-Structure.mdprisma.yml概览与示例含订阅与目录结构docs/1.12/04-Reference/02-Service-Configuration/02-prisma.yml/01-Overview--Example.mdCLI 订阅配置解析cli/packages/prisma-yml/src/PrismaDefinition.ts服务器侧执行与投递server/servers/api/src/main/scala/com/prisma/api/mutactions/SideEffectMutactionExecutor.scala订阅过滤器评估与执行server/servers/api/src/main/scala/com/prisma/subscriptions/SubscriptionExecutor.scalaWebhook 数据结构server/servers/api/src/main/scala/com/prisma/subscriptions/Webhook.scala集成测试行为验证server/servers/api/src/test/scala/com/prisma/subscriptions/EmbeddedServerSideSubscriptionSpec.scala赞分享后端数据库GraphQL【免费下载链接】prisma1 Database Tools incl. ORM, Migrations and Admin UI (Postgres, MySQL MongoDB) [deprecated]项目地址https://gitcode.com/gh_mirrors/pr/prisma1点击查看免费下载相关推荐Prisma 服务端订阅Server-side Subscriptions实战指南用 Webhook 把数据库变更接入外部业务逻辑Prisma 服务端订阅Server side Subscriptions实战指南用 Webhook 把数据库变更接入外部业务逻辑 导读 服务端订阅Se后端数据库GraphQLPrisma 服务端订阅Server-side Subscriptions实战指南用 Webhook 在 Serverless 架构中消费数据变更事件Prisma 服务端订阅Server side Subscriptions实战指南用 Webhook 在 Serverless 架构中消费数据变更事件 导后端数据库GraphQL如何快速构建图像相似性搜索系统使用mobileone_s2.apple_in1k的完整指南如何快速构建图像相似性搜索系统使用mobileone_s2.apple_in1k的完整指南 在当今AI驱动的世界中图像相似性搜索已成为许多应用的核心功能。本后端数据库GraphQL创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价