- AI Agent
- 后端
- 任务调度
- 开发工具
- 可观测性
- AI 应用
【免费下载链接】trigger.dev
Trigger.dev – build and deploy durable AI agents and workflows
本篇技术指南以 Trigger.dev 仓库中"托管 Webhooks(Hosted Webhooks)"功能的控制台前端(UX/前端)开发为线索,完整梳理从零搭建本地开发环境、理解 Deliveries 数据流水线(Postgres + ClickHouse 复制)、通过种子脚本/内置 Composer/真实 Provider 三条路径造出真实可截图数据,以及前端代码地图、设计语言与提交规范的完整链路。读完本文,你可以独立把一个干净的机器跑起带真实 Webhook 数据的 dashboard,并知道每个界面背后由哪些源码支撑。
托管 Webhooks 让 Trigger.dev 用户无需自建 Ingress 与验签代码,就能把 Stripe、GitHub 等 Provider 的 Webhook 作为 Task 接收、校验并路由到自己的onEvent处理器。本文所依据的核心文档为仓库根目录下的 ONBOARDING.md(对应 PR #4344 "hosted webhooks, agent channels, and human-in-the-loop" 的交接说明),并辅以仓库源码作为实现佐证。
功能背景:托管 Webhooks 与四块待设计的界面
用户在自己项目里写一个webhook()处理器,即可获得一个托管 URL;Provider 向该 URL 投递的请求会被验证、记录,并路由到用户的onEvent处理器。Dashboard 在左侧导航 "Webhooks" 分区(青色图标)下共有四个界面归属前端设计,全部位于/orgs/:org/projects/:project/env/:env之下:
| 界面 | 路由 | 展示内容 |
|---|---|---|
| Deliveries 列表 | /webhooks | 环境中所有端点的全部投递记录。复用 Runs 风格的筛选栏(Status、Webhook、Created,以及 More-filters 菜单里的 Delivery ID / Run ID)、已应用筛选的 pills、链接到 handler 的 Webhook 列。主屏。 |
| Delivery 详情 | /webhooks/deliveries/:deliveryParam | 单条投递。主面板是选项卡视图(Event payload / Request headers),以 JSON 渲染;侧栏属性表(状态徽章、webhook 与 run 链接、external delivery id、幂等键、时间戳、计算出的耗时、错误信息),并提供针对过期/失效链接的友好空状态("not available / retained for N days")。 |
| Handler 详情 + Console | /webhooks/:webhookParam | 用户代码中的webhook()处理器。选项卡:Deliveries、Runs、Endpoints。此页还承载Webhook Console / Composer(见下文造数据章节)。 |
| Endpoint 详情 | /webhooks/endpoints/:endpointParam | 单个端点。左侧:按端点过滤的投递;右侧:Connect卡片(webhook URL、签名密钥的 set/rotate/generate、由 verifier 配置渲染出的 Provider 设置指引)、Routing、Scope、Metadata。 |
状态词汇、徽章与颜色分别集中在 DeliveryStatus.tsx 与 EndpointStatus.tsx 中。从源码可见,投递状态复用 Runs 页的十六进制色板(不新造颜色):SUCCEEDED#28BF5C、FAILED#E11D48、PROCESSING#3B82F6、PENDING#878C99、FILTERED#64748B(已接收并验证、有意不路由,属中性色而非失败);端点状态为 ACTIVE#28BF5C、INACTIVE#878C99、DELETING#F59E0B。导航强调色是 Tailwind token--color-webhooks(teal),定义于 tailwind.css(--color-webhooks: var(--color-teal-500)),通过text-webhooks使用,侧边栏的注入点见 SideMenu.tsx。
环境准备:分支、工具链与依赖安装
该功能的后端已全部就绪,前端设计工作基于特性分支feat/hosted-webhook-ingress:
git clone https://gitcode.com/gh_mirrors/tr/trigger.dev cd trigger.dev # 使用 gh 检出对应 PR 分支(会落到 feat/hosted-webhook-ingress) gh pr checkout 4344若计划把设计改动推回该分支,需先与维护者协调:该分支会被周期性 rebase 与 force-push,应约定推送时机,或改在子分支上开发并另开跟进 PR。
工具链要求 pnpm 10.33.2(经 corepack)与 Node 22+,且必须用corepack pnpm(裸的全局pnpm可能是旧版本,会清掉node_modules):
corepack enable corepack pnpm install启动本地栈:四个基础服务与 webapp
从仓库根目录依次执行。第一步拉起核心开发服务:Postgres、Redis、Electric、MinIO、ClickHouse、s2-lite。
# 1. 核心开发服务 corepack pnpm run docker # 2. 配置 cp .env.example .env关键一步:编辑.env并追加两行 Webhook 投递复制(replication)配置。这两行不在.env.example中,缺失会导致即使发送了 Webhook,Deliveries 列表依然为空(原因见下一节):
# webhook deliveries replication(Deliveries 列表/详情填充所必需) WEBHOOK_DELIVERIES_REPLICATION_CLICKHOUSE_URL=http://default:password@localhost:8123 WEBHOOK_DELIVERIES_REPLICATION_ENABLED=1随后迁移、种子、构建并运行:
corepack pnpm run db:migrate corepack pnpm run db:seed # 创建 References 组织 + hello-world 项目 # 顺序构建将要运行的组件(勿与 db:seed 同时进行) corepack pnpm run build --filter webapp --filter trigger.dev --filter "@trigger.dev/sdk" # 运行 webapp(http://localhost:3030) corepack pnpm run dev --filter webapp curl -s http://localhost:3030/healthcheck # 验证开发环境登录:打开 http://localhost:3030,提交邮箱local@trigger.dev。开发模式下会自动验证 magic link(注意观察 webapp 日志中的/magic?token=)。该种子用户是组织管理员,这对下一步的特性开关很关键。webapp 端口来自REMIX_APP_PORT,回退到PORT/3030。
开启特性:hasWebhooksAccess 标志
Dashboard 由特性标志hasWebhooksAccess(默认关闭)控制:
- 种子开发用户
local@trigger.dev是管理员,管理员绕过该标志,因此在全新 seed 后 "Webhooks" 导航分区对你已经可见,无需额外操作; - 如果使用非管理员用户,需要在
Organization行上设置featureFlags.hasWebhooksAccess = true才能显示导航分区。注意:全局FeatureFlag行(key 为hasWebhooksAccess)只能让页面按 URL 直达,左侧导航只读组织级标志,所以非管理员的分区依然隐藏。
如果左侧导航缺少 "Webhooks" 分区,原因就是该标志。
数据流水线:为什么列表可能为空
理解数据流向是排查"列表为空"的关键:
ingest -> engine(verify、filter、route)-> Postgres WebhookDelivery 行 -> replication -> ClickHouse从 WebhookDeliveriesListPresenter.server.ts 的实现可见:Deliveries列表的排序与分页来自 ClickHouse,随后每个可见字段再从 Postgres 水合(hydrate)——包括解析 run 的 friendlyId、会话归属,以及为 "Webhook" 列解析每个投递所属的 handler(handlerWebhookId与source)。因此若复制关闭(第三节),你能创建投递却看到空列表。启用两个复制环境变量并重启 webapp 即可。
一个内置于设计的注意事项:复制从开启那一刻才开始流式传输,所以开启之前写入的投递不会出现。务必先开复制,再造数据。
此外,列表页支持跨端点全量查询:页大小固定为 60(DELIVERIES_PAGE_SIZE = 60);筛选器中的 webhook(handler slug)会被解析为端点 ID 集合、runId 会被解析为内部 ID,且当筛选命中为空时会解析为哨兵值"__none__",保证"筛选后无结果"而非"筛选被静默丢弃";countNewDeliveries用与列表一致的筛选逻辑统计"N 条新投递"徽章。投递详情页则直接读 Postgres——它是事件 payload 与请求头唯一的持久副本。
造数据三路径
投递行正是这些界面"好看"的关键:丰富的 Provider、状态、payload、时间戳。下面按文档给出的三条路径逐一展开,并给出源码佐证。
路径一:一键种子脚本(推荐)
仓库提供一个种子脚本,直接把完整、稳定的数据集写入两个存储(Postgres 与 ClickHouse),无需任何 worker、trigger dev或签名密钥配置即可在全新 DB 上得到真实的界面数据:
corepack pnpm --filter webapp run db:seed:webhooks # 可选:每个端点的投递数(默认 45) corepack pnpm --filter webapp run db:seed:webhooks -- 60脚本入口为 seed-webhook-deliveries.ts(npm 脚本db:seed:webhooks在 apps/webapp/package.json 中定义为varlock run --inject vars -- tsx seed-webhook-deliveries.ts)。从源码可以确认其行为细节:
- 六个端点覆盖不同 Provider 与验签方案:Stripe、GitHub、Slack、Svix、Discord(非对称 ed25519)以及一个自定义共享密钥端点,且混合了 active/inactive 与 secret-set/not-set(见
ENDPOINTS数组,seed-webhook-deliveries.ts); - 每种投递状态全覆盖:
STATUS_WEIGHTS按权重生成 SUCCEEDED(68)、FAILED(12)、FILTERED(11)、PROCESSING(4)、PENDING(5)(seed-webhook-deliveries.ts),FAILED 带真实失败原因(签名验证失败、未设置签名密钥、时间戳超出容差窗口),FILTERED 带event.type不匹配的 filter reason; - 最近两周的时间分布,且偏向近期(
biasedCreatedAt使用Math.random() ** 1.7加权),并混有 test/live(约 15% 为测试投递); - 每个 Provider 的真实感 payload 与签名头:如 Stripe 的
Stripe-Signature、GitHub 的X-Hub-Signature-256、Slack 的X-Slack-Signature、Svix 的webhook-signature、Discord 的X-Signature-Ed25519等; - 脚本附着到本地用户可见的第一个 DEVELOPMENT 环境(可用
WEBHOOK_SEED_PROJECT="<project name>"指定项目),完成后会打印精确的 Deliveries URL; - 可重跑:每次运行先清空该环境的投递再重新种子,保证始终得到同一份干净数据;残留的 ClickHouse 行会因列表丢弃"Postgres 行已不存在"的有序 ID 而自动隐藏;
- 因为直接写 ClickHouse,种子数据无需第三节的复制配置即可显示;复制环境变量只在"实时"与 Composer 路径下需要。种子优先使用
WEBHOOK_DELIVERIES_REPLICATION_CLICKHOUSE_URL,未设置时回退到CLICKHOUSE_URL(后者已在.env.example中); - 细节陷阱在源码注释中有明确提醒:投递的
friendlyId必须是whd_前缀加 id(详情页按whd_剥前缀后用id查 Postgres),两者若独立铸造会导致每个种子投递的详情页 404; - 脚本还会按需创建按天的 ClickHouse 分区表(
WebhookDelivery_YYYY_MM_DD),并向trigger_dev.webhook_deliveries_v1以 JSONEachRow 批量写入。
这是推荐的数据获取方式。下面的交互路径用于演练实时流水线(真实验签、真实路由 run)或应用内测试控制台。
路径二:交互式——创建端点 + Webhook Console
Composer 把投递发给端点,而端点只有在声明了webhook()的 Trigger 项目被 dev-run 或部署后才会存在。最快的方式是建一个微型 demo 项目:
// demo/src/trigger/demo-webhook.ts import { webhook, webhooks } from "@trigger.dev/sdk"; export const demoWebhook = webhook({ id: "demo-webhook", source: webhooks.custom<{ message: string }>({ /* generic HMAC */ }), onEvent: async ({ event, headers, ctx }) => { // event 是解析后的 body,headers 是 Web Headers 对象 }, }); // 真实 Provider,用于真实感 payload: export const stripeWebhook = webhook({ id: "stripe-webhook", source: webhooks.stripe(), onEvent: async ({ event }) => {}, });将该 demo 项目链接到本地构建并运行trigger dev(参见仓库 AGENTS.md 中 "Testing with the hello-world Reference Project" 的链接说明;triggerdotdev/references仓库提供现成项目)。trigger dev会注册webhook()处理器从而创建对应端点。随后在 endpoint 详情页的 Connect 卡片中为每个端点设置签名密钥(Generate 或粘贴)。
打开 handler 详情页(/webhooks/:webhookParam)即进入内置的Composer(组件 WebhookComposer.tsx 的源码位于 apps/webapp/app/components/webhookConsole/WebhookComposer.tsx)。它直接把投递在进程内注入引擎,速度快且不消耗真实速率额度。四个来源选项卡与四种签名模式(源码中SourceTab与SignatureMode类型定义见 WebhookComposer.tsx):
| 来源选项卡 | 说明 |
|---|---|
| Body | 手写任意 JSON(内置 JSON 编辑器,默认 body 为{"message": "hello from the webhook console"}) |
| Library(Sample) | 从内置事件目录(@internal/webhook-sources,六个一级 Provider 外加大型 sample manifest,目录见 internal-packages/webhook-sources)挑选真实 Provider 事件,是获取正确外观 Stripe / GitHub / Svix / Square / Discord payload 与头的最快方式 |
| Replay | 重发一条既有投递 |
| AI | 用提示词生成 payload |
| 签名模式 | 行为 |
|---|---|
signed | 用端点存储的密钥服务端签名;验证通过并路由到 SUCCEEDED 投递(端点未设密钥或为 asymmetric 方案时该选项禁用并给出原因提示) |
simulate | 跳过验签注入,但 filter、startOn、路由与 run 依然执行 |
unsigned | 预期返回 400,产生失败/拒绝投递 |
tampered | 预期返回 400,产生失败/拒绝投递(fail-closed,不写投递行) |
这正是制造状态分布的手法:signed(配合已设密钥)产出 SUCCEEDED,unsigned与tampered产出失败/拒绝。此外还有几个值得留意的 Composer 细节:可选 Headers 编辑器(签名头自动附加,可加x-github-event等路由头);Webhook URL 的剪贴板展示(标注 POST,为 Provider 投递的公网地址,测试发送在进程内跑同一流水线);handshake 发送按钮(依据 verifier 配置构造 challenge body 并期望端点回显,握手内联应答、不记录投递);相同 payload 会被去重到原投递(结果条显示 "Deduplicated" 徽章);非开发环境发送前弹确认对话框并给出警告 Callout。结果条会显示 HTTP 状态 / Handshake / Deduplicated 徽章、投递 ID 与 "View delivery" 跳转链接。
要想得到 SUCCEEDED 且其 run 也完成的最完整端到端数据,请保持 demo 项目的trigger dev运行,让被路由的 task 真正执行。
路径三:真实 Provider(最真实)
想要真正的 payload 与请求头,可把 Stripe CLI 指向端点:
stripe listen --forward-to http://localhost:3030/webhooks/v1/ingest/<opaqueId>先在 Connect 卡片里为该端点设置whsec,然后stripe trigger payment_intent.succeeded。各 Provider 的验签配置(签名头、时间戳容差、签名串模板、幂等字段)在 packages/core/src/v3/webhooks/index.ts 中有纯数据形式的单一定义(如stripeVerifierConfig、githubVerifierConfig、svixVerifierConfig、standardWebhooksVerifierConfig),SDK 的webhooks.stripe()等生产者与样本目录共用这份来源。
前端代码地图
以下是前端各区域的代码位置速查表:
| 区域 | 路径 |
|---|---|
| 路由(页面) | apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.webhooks/ 及webhooks._index、webhooks.$webhookParam、webhooks.deliveries.$deliveryParam、webhooks.endpoints.$endpointParam等文件 |
| Deliveries 列表/详情组件 | apps/webapp/app/components/webhookDeliveries/v1/(DeliveriesTable、DeliveryStatus、WebhookDeliveryFilters、DeliveryTimeline、useDeliveriesLiveReload) |
| Endpoint 组件 | apps/webapp/app/components/webhookEndpoints/v1/(EndpointsTable、EndpointStatus) |
| Console / Composer | apps/webapp/app/components/webhookConsole/(WebhookComposer、SampleSourcePicker、ReplaySourcePicker) |
| 数据(presenter,只读侧) | apps/webapp/app/presenters/v3/WebhookDeliveriesListPresenter.server.ts、WebhookDeliveryDetailPresenter.server.ts、WebhookDetailPresenter.server.ts、webhookComposerEndpoints.server.ts |
| 导航入口 | apps/webapp/app/components/navigation/SideMenu.tsx(staticSections中的 "webhooks" push,配合text-webhooks) |
| 路径构建器 | apps/webapp/app/utils/pathBuilder.ts(v3WebhooksPath、v3WebhookTaskPath、v3WebhookDeliveryPath、v3WebhookEndpointPath) |
| 强调色 token | apps/webapp/app/tailwind.css(--color-webhooks,用法text-webhooks) |
| 数据种子脚本 | apps/webapp/seed-webhook-deliveries.ts(经db:seed:webhooks运行) |
Composer 背后的资源路由(发送、样本、重放来源、实时投递)位于apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.webhooks.*,例如webhooks.endpoints.$endpointParam.send.ts、webhooks.samples.ts、webhooks.endpoints.$endpointParam.replay-source.ts、webhooks.deliveries.live.ts;投递重放 API 见apps/webapp/app/routes/api.v1.webhooks.deliveries.$deliveryId.replay.ts,端点密钥轮换/启停见api.v1.webhooks.endpoints.$endpointId.{rotate-secret,enable,disable}.ts。
样式体系:webapp 使用 Tailwind v4(CSS-first 的@theme,位于 apps/webapp/app/tailwind.css,不存在tailwind.config.js)。新增或修改设计 token 都在该文件进行。
需要匹配的设计语言:这些界面刻意复用 Runs 页原语——筛选栏由RunFilters/SharedFilters构建,表格沿用 Runs 表格单元格。请对齐 Runs 与 Sessions 页面,而不是另立一套视觉体系。
迭代工作流
- HMR vs 重启:编辑组件(
.tsx)热更新;编辑.server.ts文件会让 Remix dev server 重启应用(短暂 connection refused 后恢复);编辑 Tailwind token 热更新。 - 截图:从运行中的 dashboard(http://localhost:3030)截图,保存到仓库外或 scratch 目录,避免误提交。
- 非平凡改动后跑类型检查:
corepack pnpm run typecheck --filter webapp(约 1~2 分钟)。小型样式调整可信任 CI 兜底。 - 一个 dev server 不会捕获的边界陷阱:路由文件绝不能把 server-only import 泄漏进客户端 bundle——dev server 能容忍,但生产构建会失败。若你动了路由文件并引入任何 server-only 导入,推送前务必执行
corepack pnpm --filter webapp run build:remix。纯组件与样式改动不受影响。
提交与 CI
- 提交前先格式化与 lint:
corepack pnpm run format(oxfmt)与corepack pnpm run lint:fix(oxlint),CI 两者都强制。 - 提交风格为 Conventional Commits,例如
feat(webapp): redesign webhook deliveries table;不加 emoji,不加署名 footer。 - PR 保持draft状态等待 AI review pass 再转人工 review,之后才置为 ready;不要自行翻转,推送提交后由维护者协调 review 与 rebase 到
main。 - 需要关注的 CI:
code-quality(oxfmt + oxlint)、typecheck、webapp 单元分片,以及 Playwrighte2e-webapp任务。纯样式改动通常只影响code-quality。
快速参考速查表
- Webapp:http://localhost:3030(端口来自
REMIX_APP_PORT,回退PORT/3030) - 默认 docker 服务:Postgres 5432、Redis 6379、ClickHouse HTTP 8123(
default:password)、MinIO、Electric、s2-lite - 特性标志:
hasWebhooksAccess(管理员绕过) - 种子数据:
corepack pnpm --filter webapp run db:seed:webhooks(追加-- <n>控制每端点投递数) - 必设环境变量(数据要显示):
WEBHOOK_DELIVERIES_REPLICATION_ENABLED=1与WEBHOOK_DELIVERIES_REPLICATION_CLICKHOUSE_URL=http://default:password@localhost:8123 - 登录:
local@trigger.dev,开发环境自动验证 magic link
心智模型:一段话总结
用户在自己的项目中写一个webhook()。在部署(或trigger dev)时,该 handler 会获得一个或多个托管端点,每个端点带签名密钥。Provider 向端点的 URL 发 POST;引擎验签、可选过滤、记录一条WebhookDelivery,并触发被路由的 task run。Dashboard 读取这些投递:列表从 ClickHouse 排序取数并从 Postgres 水合其余字段,详情页直接读 Postgres(那里保存着事件 payload 与请求头的唯一副本)。你要设计的一切,都落在"那条投递记录"与"产生它的那个端点"之上。
- AI Agent
- 后端
- 任务调度
- 开发工具
- 可观测性
- AI 应用
【免费下载链接】trigger.dev
Trigger.dev – build and deploy durable AI agents and workflows
相关推荐
如何快速搭建Trigger.dev本地开发环境:Docker Compose完整指南
如何快速搭建Trigger.dev本地开发环境:Docker Compose完整指南 Trigger.dev是一个强大的开源工具,可帮助开发者构建和部署全托管的
AI Agent后端任务调度开发工具可观测性AI 应用Cookiecutter Django 本地开发环境搭建完全指南:从裸机同步开发到异步任务与前端流水线
Cookiecutter Django 本地开发环境搭建完全指南:从裸机同步开发到异步任务与前端流水线 本篇指南以 Cookiecutter Django 项目
后端代码生成开发工具Kafka-UI React 前端:从零搭建 Apache Kafka 管理界面的开发环境实战指南
Kafka UI React 前端:从零搭建 Apache Kafka 管理界面的开发环境实战指南 UI for Apache Kafka(即 kafka ui
后端前端可观测性消息队列
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考