- CMS
- 后端
- 前端
【免费下载链接】webiny-js
Open-source, self-hosted CMS platform on AWS serverless (Lambda, DynamoDB, S3). TypeScript framework with multi-tenancy, lifecycle hooks, GraphQL API, and AI-assisted development via MCP server. Built for developers at large organizations.
本指南基于 packages/api-sync-system/DEVELOPMENT.md,系统讲解 Webiny 开源仓库中 Sync System(同步系统)的核心概念:如何在dev等环境中通过--env与--variant参数部署多个并行的 Webiny 实例,让它们在同一个环境内自动互联、双向同步数据(文件、用户等记录)。读完本文,你将掌握 Sync System 的完整部署命令、env/variant参数语义,以及其底层 Resolver、Worker、Sync Handler 三大组件的真实源码结构与待办路线图。
Sync System 是什么:一个环境内多实例自动互联的同步层
在 Webiny 中,Sync System 是一套负责将**同一环境(env)下多个 Webiny 部署(deployment)**之间的数据保持一致的独立基础设施。它解决的核心问题是:
- 同一套 Webiny 系统可以部署多个副本(例如
blue与green两个 variant),各自拥有独立的 DynamoDB、S3 与用户体系; - 当用户在
blue中创建或修改文件、用户等记录时,这些变更需要自动同步到green(反之亦然); - 多个实例可以随时加入(部署数量不限于两个),只要使用不同的
variant即可。
从源码结构看,这个能力被收敛在 packages/api-sync-system 这一个独立包中,其package.json描述即为 "Sync System.",依赖@webiny/aws-sdk、@webiny/event-handler-aws、@webiny/feature、@webiny/plugins、zod等基础设施库。包内主要由三大部分组成,对应三条不同的运行路径:
| 组件 | 源码目录 | 职责 |
|---|---|---|
| Sync System | packages/api-sync-system/src/sync | 通过ApiGatewaySyncDecorator装饰 API Gateway 事件处理链,拦截 DynamoDB 写操作并生成同步命令,再通过 EventBridge 发布事件 |
| Resolver | packages/api-sync-system/src/resolver | 由 SQS 事件触发,拉取各 deployment 的元数据与源数据,将同步命令转换为目标 deployment 的 DynamoDB 写操作 |
| Worker | packages/api-sync-system/src/worker | 由 Lambda 触发,执行跨系统拷贝类动作(S3 文件复制、Cognito 用户创建/更新/删除) |
三个组件的公开 API 全部从 packages/api-sync-system/src/index.ts 导出:SyncResolverConfig/SyncResolverLambdaHandler、SyncWorkerConfig/SyncWorkerEventType/SyncWorkerEventHandler/SyncWorkerLambdaHandler,以及SyncSystemConfig/ApiGatewaySyncDecorator。
理解env与variant参数
DEVELOPMENT.md 开篇首先澄清了两个关键参数:
env(环境):指 Webiny 的部署环境,示例中一律使用dev。你也可以使用staging、prod等环境名;variant(变体):用于在同一环境内区分多个并行部署的任意标识。示例使用blue和green,但你完全可以用orange、black、car、horse、space等任意字符串。
关键约束:Sync System 与各个 Webiny 部署必须处于同一个env中,因为 Sync System 会自动连接同一环境内的所有 Webiny 部署(通过解析各部署写入 DynamoDB 的 deployment 记录)。同一环境下可以使用任意数量的 variant,唯一的硬性要求是每个部署使用不同的 variant。
这一点可以从 packages/api-sync-system/src/resolver/deployment/Deployment.ts 得到印证:Deployment类显式持有name、env、variant、region、services、version六个字段,其中variant是可选字段(string | undefined),而getTable(type)方法根据 deployment 的services返回regular(主 DynamoDB 表)或opensearch(OpenSearch 数据表)两种表类型。也就是说,Resolver 在同步时是按"环境 + variant + 区域"去定位目标表的。
三步部署流程:从 Sync System 到多实例安装
1. 部署 Sync System
在项目根目录执行:
yarn webiny deploy sync --env=dev该命令将 Sync System 部署到dev环境。它对应的就是包中sync目录(packages/api-sync-system/src/sync)所承载的运行时能力,包括createHandler(sync/createHandler.ts)与ApiGatewaySyncDecorator(sync/ApiGatewaySyncDecorator.ts)。
2. 部署blue与green两个 Webiny
yarn webiny deploy --env=dev --variant=blue && yarn webiny deploy --env=dev --variant=green这里&&串联意味着blue部署成功后才部署green。文档特别强调:两个系统必须与 Sync System 处于同一环境,Sync System 才能自动识别并连接它们。并且部署数量可以超过两个——只要保证 variant 不同即可。
3. 安装 Webiny Blue 变体
先查看部署信息,找到bluevariant 的 Admin URL:
yarn webiny info然后在浏览器中打开该 Admin URL,按照界面指引完成系统安装。安装完成后,green系统也会被同步安装——这正是 Sync System 的核心价值:一次安装,多实例就绪。
Resolver:把源系统变更"搬运"到目标系统
Resolver 是同步链条中的核心执行者,由 resolver/SyncResolverLambdaHandler.ts 实现,并通过SqsEventHandler.createImplementation注册为 SQS 事件处理器。其处理流程(processResolverEvent)可以概括为:
- 取配置:
tableName取自config.tableName || process.env.DB_TABLE,若两者都为空则抛出WebinyError("Table name variable is not set."); - 建 Fetcher:
createFetcher({ maxRetries: 10, retryDelay: 1000, ... })按 deployment 的region创建 DynamoDB Document Client,负责从源系统读取记录,最多重试 10 次、每次间隔 1 秒; - 拉取 Deployments:
createDeploymentsFetcher从当前 region 读取所有 deployment 元数据(即上面Deployment类对应的记录),得到需要同步的目标集合; - 建 Storer:
createStorer同样按目标 deployment 的 region 写入数据,且支持StorerAfterEachPlugin插件在每个写入完成后做后续处理; - 变换与打包:
TransformHandler+RecordHandler配合createBundler(CommandBundle与TableBundle两种打包器)将源记录转换成目标表的写命令; - 执行:
createResolverApp(...).resolve({ records })逐个处理 SQS 消息中的记录。
Resolver 还负责触发"拷贝类"动作:在 SyncResolverLambdaHandler.ts 的execute中,会依据config.createLambdaClient与config.awsWorkerLambdaArn || process.env.AWS_SYNC_WORKER_LAMBDA_ARN创建LambdaTrigger,进而构造CopyFile/DeleteFile(依赖 S3 客户端)与CopyUser/DeleteUser(依赖 Cognito Identity Provider 客户端),再把它们注册进PluginsContainer供记录处理链调用。这正是文档 TODO 中提到"给 Sync System handlers 传一堆方法"的根源——详见下文配置注入部分。
Worker:跨系统执行文件复制与用户账号操作
Worker 由 worker/SyncWorkerLambdaHandler.ts 实现,注册为SyncWorkerEventHandler。其职责是接收 Resolver 通过LambdaTrigger发来的动作请求,执行无法在 DynamoDB 层完成的跨系统操作:
createCopyFileAction/createDeleteFileAction:基于 S3 客户端复制或删除文件;createCreateUserAction/createUpdateUserAction/createDeleteUserAction:基于 Cognito 客户端创建、更新、删除用户。
动作类型定义在 worker/SyncWorkerEventType.ts,动作分发由 worker/handler/WorkerActionHandler.ts 完成,可扩展点是通过 worker/plugins/WorkerActionPlugin.ts 注册自定义动作。对应地,Resolver 侧的记录类型插件位于 resolver/recordTypes/fileManager 与 resolver/recordTypes/users,分别处理文件与用户的复制/删除语义。
Sync System 的接入方式:ApiGatewaySyncDecorator 与命令转换
同步入口不是独立运行的 Lambda,而是以装饰器形式挂在 API Gateway 事件处理器上。sync/ApiGatewaySyncDecorator.ts 的核心逻辑:
- 调用
getManifest()(sync/utils/manifest.ts)读取同步 manifest;若 manifest 缺失或没有sync.region,打印[ApiGatewaySyncDecorator] Manifest not available — sync disabled.并直接放行(同步被禁用); - 通过
createHandler(sync/createHandler.ts)构建同步处理器。createHandler会注册一批命令转换器(CommandConverter):BatchGet、Get、Query、Scan、BatchWrite、Put、Delete、Update,默认值使用NullCommandValue,并读取FilterOutRecordPlugin插件用于过滤不需要同步的记录; - 用
decorateClientWithHandler(sync/attachToDynamoDbDocument.ts)把 handler 挂到 Document Client 上,从而拦截应用内部的 DynamoDB 写操作,将其转换为同步命令; - 在内层处理器执行结束后调用
handler.flush(),确保命令被批量发出(事件通过 manifest 中的eventBusArn/eventBusName发布到 EventBridge,见 sync/createHandler.ts)。
需要同步的写操作会在 EventBridge 上以synchronization-input事件名出现(见 constants.ts),之后由 Resolver 的 SQS 处理器消费。
配置注入方式与文档中的依赖注入展望
文档 TODO 中明确指出了当前实现的一个痛点:Sync handlers 需要调用者传入大量"creator 方法"。当前SyncResolverConfig(resolver/SyncResolverConfig.ts)的接口确实包含:
export interface ISyncResolverConfig { tableName?: string; awsWorkerLambdaArn?: string; createDocumentClient(params: Partial<DynamoDBClientConfig>): Pick<DynamoDBDocument, "send">; createLambdaClient?(config: Partial<LambdaClientConfig>): Pick<LambdaClient, "send">; createS3Client?(config: S3ClientConfig): Pick<S3Client, "send">; createCognitoIdentityProviderClient?(config: Partial<CognitoIdentityProviderClientConfig>): Pick<CognitoIdentityProvider, "send">; plugins?: AllowedResolverPlugins[]; }即当前实际用法接近文档中的"冗长版本":
const handler = createSyncResolverHandler({ plugins: [], debug: process.env.DEBUG === "true", awsWorkerLambdaArn: process.env.AWS_SYNC_WORKER_LAMBDA_ARN, createS3Client, createLambdaClient, createDocumentClient, createCognitoIdentityProviderClient });而文档展望的理想形态是"轻量版本"——只需传入plugins、debug与awsWorkerLambdaArn三项:
const handler = createSyncResolverHandler({ plugins: [], debug: process.env.DEBUG === "true", awsWorkerLambdaArn: process.env.AWS_SYNC_WORKER_LAMBDA_ARN });文档将其归结为 TODO 中的Implement Dependency Injection:若引入依赖注入框架,各 creator 方法(createS3Client、createLambdaClient、createDocumentClient、createCognitoIdentityProviderClient)即可由框架自动装配,调用方无需逐个传入,后续新增方法也不必改动调用点。这是当前包内尚未落地的演进方向。
文档中的其他 TODO:已知问题与演进路线
DEVELOPMENT.md 还记录了若干待办事项,理解它们有助于判断 Sync System 当前的成熟度与边界:
- 新增
blueGreen、sync/resolver、sync/worker目录到用户项目:目前需要把这些文件夹部署进用户项目(也许做成一个 CLI 命令更佳); - Blue/Green 部署端到端测试:文档给出完整的测试清单——创建
api.bg.webiny.com、admin.bg.webiny.com、website.bg.webiny.com、preview.bg.webiny.com域名,部署 blueGreen 应用,确认域名指向正确,在 blue/green 之间切换以测试 resolver,并在两侧创建/更新记录、确认数据正确传递; - Cognito 用户迁移缺陷:用户账号目前可以转移,但密码没有迁移,导致用户无法登录也无法重置密码;计划通过实现一个登录函数——向用户邮箱发送验证码、凭验证码完成登录——来彻底解决;
- 删除记录的模型过滤:目前模型过滤只在记录加入同步池时(创建/更新)生效,而删除操作没有携带
modelId,无法过滤;文档提出"也许可以在 resolver 中实现过滤"; - 接入 pino 日志:用 pino 替代现状,按
info、warn、error、debug等级别记录所有事件。从源码看,当前 handler 在出错时使用console.error/console.log(见 SyncResolverLambdaHandler.ts 与 SyncWorkerLambdaHandler.ts),这也与仓库中 no-console-in-backend 的代码风格约束相呼应; - 拆分 Resolver 插件:把 file manager、users 的 resolver 插件迁移到各自独立的包中,由对应包自行注册(当前这些插件集中在 resolver/recordTypes 下)。
快速上手:完整命令序列
综合全文,在dev环境跑通 Blue/Green 同步的完整命令序列为:
# 1. 部署 Sync System yarn webiny deploy sync --env=dev # 2. 部署两个(或多个)Webiny 实例,variant 必须不同 yarn webiny deploy --env=dev --variant=blue yarn webiny deploy --env=dev --variant=green # 3. 查看部署信息,找到 blue 的 Admin URL 并完成安装 yarn webiny info安装好blue后,green会自动完成安装;此后在任一实例中创建/更新/删除的文件与用户记录,会经由 DynamoDB 命令拦截 → EventBridge 事件 → Resolver(SQS)→ Worker(Lambda)的链路同步到另一实例。需要进一步阅读实现细节时,可深入 packages/api-sync-system/src 的sync、resolver、worker三个子目录,以及包内对应测试用例。
- CMS
- 后端
- 前端
【免费下载链接】webiny-js
Open-source, self-hosted CMS platform on AWS serverless (Lambda, DynamoDB, S3). TypeScript framework with multi-tenancy, lifecycle hooks, GraphQL API, and AI-assisted development via MCP server. Built for developers at large organizations.
相关推荐
从0到1搭建preact-render-to-string+Express服务:动态HTML生成教程
从0到1搭建preact render to string+Express服务:动态HTML生成教程 preact render to string是一个强大的
Webiny pg-os 后端 PG 到 OpenSearch 同步流(Sync Stream)流水线设计与实现指南
Webiny pg os 后端 PG 到 OpenSearch 同步流(Sync Stream)流水线设计与实现指南 导读 本文围绕 PG to OpenSea
CMS后端前端在 Kubernetes 上使用 Argo Rollouts 实现 Blue/Green 部署:devops-exercises 实操指南
在 Kubernetes 上使用 Argo Rollouts 实现 Blue/Green 部署:devops exercises 实操指南 本指南基于 devo
文档教程DevOps运维
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考