Files
twenty/packages/twenty-docs/l/zh/developers/extend/apps/config/install-hooks.mdx
T
github-actions[bot] a3a6a55051 i18n - docs translations (#23250)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-07-24 11:26:33 +02:00

189 lines
11 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: 安装钩子
description: 在安装、升级或卸载生命周期中运行逻辑——预置数据、备份记录、验证升级、清理外部资源。
icon: wrench
---
安装钩子是在安装、升级或卸载生命周期期间运行的特殊逻辑函数。 它们与常规的[逻辑函数](/l/zh/developers/extend/apps/logic/logic-functions)共享相同的处理程序运行时,但使用自己的定义函数声明,并且存在于普通触发模型(HTTP、cron、数据库事件)之外。 安装钩子接收一个 `InstallPayload``{ previousVersion?: string; newVersion: string }`——在全新安装时 `previousVersion` 为 `undefined`);卸载钩子接收一个 `UninstallPayload``{ version?: string }`——要被移除的版本)。
每个应用每种钩子(预安装、后安装、卸载)最多只能定义一个。 如果检测到任一类型多于一个,清单构建将报错。
```
┌─────────────────────────────────────────────────────────────┐
│ install flow │
│ │
│ upload package → [pre-install] → metadata migration → │
│ generate SDK → [post-install] │
│ │
│ old schema visible new schema visible │
└─────────────────────────────────────────────────────────────┘
```
## 一览
| | `definePreInstallLogicFunction` | `definePostInstallLogicFunction` |
| ---- | ------------------------------- | --------------------------------------------------------- |
| 运行 | 元数据迁移之前——**先前**的模式和数据仍然完好无损 | 迁移和 SDK 生成之后——**新的**模式已就位 |
| 执行 | 始终为同步;会阻塞安装 | 默认异步(排队,重试 3 次);可通过 `shouldRunSynchronously: true` 选择同步 |
| 失败时 | 安装在任何模式更改之前被**中止** | 异步:最多重试 3 次。 同步:调用方会收到 `POST_INSTALL_ERROR`(模式更改**不会**回滚) |
| 典型用途 | 备份或修复迁移会丢失的数据;通过抛出异常拒绝存在风险的升级 | 预填充默认数据、配置工作区、注册外部资源 |
**经验法则:** 默认使用 post-install。 仅当迁移本身具有破坏性,且你需要在其丢失之前拦截先前状态时,才使用安装前。
| 你想要... | 使用 |
| ------------------ | ------------------------------------------------ |
| 预填充数据、配置工作区、注册外部资源 | `post-install` |
| 不应阻塞安装响应的长时间运行任务 | `post-install`(默认异步模式,带工作线程重试) |
| 安装返回后调用方会立即依赖的快速设置 | `post-install`,配合 `shouldRunSynchronously: true` |
| 读取或备份即将被迁移丢失的数据 | `pre-install` |
| 拒绝会损坏现有数据的升级 | `pre-install`(从处理程序中抛出异常) |
| 在每次升级时执行对账 | 任一钩子配合 `shouldRunOnVersionUpgrade: true` |
## 两个钩子共享的行为
* 该配置等同于 `defineLogicFunction` 的配置减去触发器设置,再加上 `shouldRunOnVersionUpgrade`。
* **运行时机**:默认情况下,仅在全新安装时运行。 将 `shouldRunOnVersionUpgrade: true` 设为 true 以便在升级时也运行。 使用 `previousVersion` / `newVersion` 按升级路径分支处理。
* **幂等性很重要**:异步 post-install 可能会被重试,而且当开启 `shouldRunOnVersionUpgrade` 时,任一钩子都会在升级时重新运行。
* 会注入常规的逻辑函数环境(`APPLICATION_ID`、`APP_ACCESS_TOKEN`、`API_URL`),因此你可以使用应用的令牌调用 Twenty API。
* 该钩子会在构建时自动附加到应用清单上(`preInstallLogicFunction` / `postInstallLogicFunction`)——在 [`defineApplication()`](/l/zh/developers/extend/apps/config/application) 中无需额外引用。
* 默认的 `timeoutSeconds` 为 300,以便支持更长的设置任务,例如数据填充。
* **在开发模式下不会执行**`yarn twenty dev` 会跳过安装流程并直接同步文件,因此钩子在其中不会运行。 改为手动触发它们:
```bash filename="Terminal"
yarn twenty dev:function:exec --postInstall
yarn twenty dev:function:exec --preInstall
```
<AccordionGroup>
<Accordion title="definePostInstallLogicFunction" description="在应用工作区元数据迁移之后运行">
在应用完成安装后运行:元数据已同步、SDK 客户端已生成、新模式可被查询。 示例——在全新安装时预填充一个默认记录:
```ts src/logic-functions/post-install.ts
import { definePostInstallLogicFunction, type InstallPayload } from 'twenty-sdk/define';
import { CoreApiClient } from 'twenty-client-sdk/core';
const handler = async ({ previousVersion }: InstallPayload): Promise<void> => {
if (previousVersion) return; // fresh installs only
const client = new CoreApiClient();
await client.mutation({
createPostCard: {
__args: { data: { name: 'Welcome to Postcard', content: 'Your first card!' } },
id: true,
},
});
};
export default definePostInstallLogicFunction({
universalIdentifier: 'f7a2b9c1-3d4e-5678-abcd-ef9876543210',
name: 'post-install',
description: 'Seeds a welcome post card after install.',
timeoutSeconds: 300,
shouldRunOnVersionUpgrade: false,
shouldRunSynchronously: false,
handler,
});
```
`shouldRunSynchronously` 标志控制执行模型:
* `false` *(默认)*——放入消息队列(`retryLimit: 3`)并由工作线程运行。 安装响应会在任务被放入队列后立即返回。 **用于长时间运行的任务**——例如预填充大型数据集、调用缓慢的第三方 API。
* `true`——在安装流程中内联执行。 安装请求会阻塞直至处理程序完成;抛出的错误会以 `POST_INSTALL_ERROR` 的形式暴露给调用方(不重试)。 **用于必须在返回响应前完成的快速任务。** 此时迁移已应用,因此失败不会回滚模式更改——只会将错误暴露出来。
</Accordion>
<Accordion title="definePreInstallLogicFunction" description="在应用工作区元数据迁移之前运行">
在元数据迁移之前、针对**先前**模式运行——适合在迁移会删除数据前对其进行备份,或拒绝存在风险的升级。 在执行之前,服务器会运行一次纯增量的“精简同步”,仅注册新版本的 pre-install 函数;当你的处理程序运行时,其他一切——上一版本的对象、字段和数据——都不会被触及。
安装前始终为**同步**,并会阻塞安装。 如果处理程序抛出异常,安装会在任何模式更改之前被中止——工作区将保持在上一版本且处于一致状态。 这是有意为之:安装前是你拒绝高风险升级的最后机会。
示例——在迁移删除旧字段之前复制该旧字段的值:
```ts src/logic-functions/pre-install.ts
import { definePreInstallLogicFunction, type InstallPayload } from 'twenty-sdk/define';
import { CoreApiClient } from 'twenty-client-sdk/core';
const handler = async ({ previousVersion, newVersion }: InstallPayload): Promise<void> => {
// Only the 1.x → 2.x upgrade drops the legacy `notes` field.
if (!previousVersion?.startsWith('1.') || !newVersion.startsWith('2.')) {
return;
}
const client = new CoreApiClient();
const { postCards } = await client.query({
postCards: {
__args: { filter: { notes: { isNot: null } } },
edges: { node: { id: true, notes: true } },
},
});
// Copy legacy `notes` into `description` before the migration drops the
// column. If this fails, the upgrade aborts and the workspace stays on v1.
for (const { node } of postCards.edges) {
await client.mutation({
updatePostCard: {
__args: { id: node.id, data: { description: node.notes } },
id: true,
},
});
}
};
export default definePreInstallLogicFunction({
universalIdentifier: 'a1b2c3d4-5678-90ab-cdef-1234567890ab',
name: 'pre-install',
description: 'Backs up legacy notes into description before the v2 migration.',
timeoutSeconds: 300,
shouldRunOnVersionUpgrade: true,
handler,
});
```
</Accordion>
</AccordionGroup>
## 卸载钩子
`defineUninstallLogicFunction` 声明一个在用户卸载你的应用时运行的钩子。 它在应用的元数据、数据和代码被移除之前执行——一旦删除迁移运行完成,就不再有任何内容可供执行——因此你的处理程序仍然可以查询应用的对象和记录。 将其用于清理外部资源:取消预置 API 资源、删除剩余的机器人、撤销网络钩子。
备注:
* 该钩子是尽力执行:它同步运行,但失败会被记录,并且**绝不会阻止卸载**——清理操作绝不能导致应用无法被移除。
* 它接收 `UninstallPayload``{ version?: string }`——要被移除的版本)。
* 在回滚失败的全新安装时,它**不会**运行——该应用从未完成安装。
* 钩子无法在应用被删除后运行,因此依赖应用数据的外部清理(例如存储在记录中的机器人 ID)应放在这里,而不是放在外部计划任务中。
* 与安装钩子类似,它在开发模式下**不会执行**——请改为手动触发:
```bash filename="Terminal"
yarn twenty dev:function:exec --uninstall
```
```ts src/logic-functions/uninstall.ts
import { defineUninstallLogicFunction, type UninstallPayload } from 'twenty-sdk/define';
import { CoreApiClient } from 'twenty-client-sdk/core';
const handler = async (_payload: UninstallPayload): Promise<void> => {
const client = new CoreApiClient();
const { meetingBots } = await client.query({
meetingBots: { edges: { node: { id: true, externalBotId: true } } },
});
// Delete the provider-side bots so nothing keeps recording after uninstall.
for (const { node } of meetingBots.edges) {
await fetch(`https://api.recorder.example/bots/${node.externalBotId}`, {
method: 'DELETE',
headers: { Authorization: `Bearer ${process.env.RECORDER_API_KEY}` },
});
}
};
export default defineUninstallLogicFunction({
universalIdentifier: 'b2c3d4e5-6789-01bc-def0-234567890abc',
name: 'uninstall',
description: 'Deletes remaining recorder bots when the app is uninstalled.',
timeoutSeconds: 300,
handler,
});
```