news 2026/10/23 12:50:14

Webiny Sync System 开发指南:Blue/Green 环境同步架构、部署流程与 Resolver/Worker 源码实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Webiny Sync System 开发指南:Blue/Green 环境同步架构、部署流程与 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.

项目地址:https://gitcode.com/gh_mirrors/we/webiny-js
点击查看免费下载

本指南基于 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 Systempackages/api-sync-system/src/sync通过ApiGatewaySyncDecorator装饰 API Gateway 事件处理链,拦截 DynamoDB 写操作并生成同步命令,再通过 EventBridge 发布事件
Resolverpackages/api-sync-system/src/resolver由 SQS 事件触发,拉取各 deployment 的元数据与源数据,将同步命令转换为目标 deployment 的 DynamoDB 写操作
Workerpackages/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)可以概括为:

  1. 取配置:tableName取自config.tableName || process.env.DB_TABLE,若两者都为空则抛出WebinyError("Table name variable is not set.");
  2. 建 Fetcher:createFetcher({ maxRetries: 10, retryDelay: 1000, ... })按 deployment 的region创建 DynamoDB Document Client,负责从源系统读取记录,最多重试 10 次、每次间隔 1 秒;
  3. 拉取 Deployments:createDeploymentsFetcher从当前 region 读取所有 deployment 元数据(即上面Deployment类对应的记录),得到需要同步的目标集合;
  4. 建 Storer:createStorer同样按目标 deployment 的 region 写入数据,且支持StorerAfterEachPlugin插件在每个写入完成后做后续处理;
  5. 变换与打包:TransformHandler+RecordHandler配合createBundler(CommandBundle与TableBundle两种打包器)将源记录转换成目标表的写命令;
  6. 执行: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 的核心逻辑:

  1. 调用getManifest()(sync/utils/manifest.ts)读取同步 manifest;若 manifest 缺失或没有sync.region,打印[ApiGatewaySyncDecorator] Manifest not available — sync disabled.并直接放行(同步被禁用);
  2. 通过createHandler(sync/createHandler.ts)构建同步处理器。createHandler会注册一批命令转换器(CommandConverter):BatchGet、Get、Query、Scan、BatchWrite、Put、Delete、Update,默认值使用NullCommandValue,并读取FilterOutRecordPlugin插件用于过滤不需要同步的记录;
  3. 用decorateClientWithHandler(sync/attachToDynamoDbDocument.ts)把 handler 挂到 Document Client 上,从而拦截应用内部的 DynamoDB 写操作,将其转换为同步命令;
  4. 在内层处理器执行结束后调用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 当前的成熟度与边界:

  1. 新增blueGreen、sync/resolver、sync/worker目录到用户项目:目前需要把这些文件夹部署进用户项目(也许做成一个 CLI 命令更佳);
  2. Blue/Green 部署端到端测试:文档给出完整的测试清单——创建api.bg.webiny.com、admin.bg.webiny.com、website.bg.webiny.com、preview.bg.webiny.com域名,部署 blueGreen 应用,确认域名指向正确,在 blue/green 之间切换以测试 resolver,并在两侧创建/更新记录、确认数据正确传递;
  3. Cognito 用户迁移缺陷:用户账号目前可以转移,但密码没有迁移,导致用户无法登录也无法重置密码;计划通过实现一个登录函数——向用户邮箱发送验证码、凭验证码完成登录——来彻底解决;
  4. 删除记录的模型过滤:目前模型过滤只在记录加入同步池时(创建/更新)生效,而删除操作没有携带modelId,无法过滤;文档提出"也许可以在 resolver 中实现过滤";
  5. 接入 pino 日志:用 pino 替代现状,按info、warn、error、debug等级别记录所有事件。从源码看,当前 handler 在出错时使用console.error/console.log(见 SyncResolverLambdaHandler.ts 与 SyncWorkerLambdaHandler.ts),这也与仓库中 no-console-in-backend 的代码风格约束相呼应;
  6. 拆分 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.

项目地址:https://gitcode.com/gh_mirrors/we/webiny-js
点击查看免费下载
上一篇:探秘 `delete-tweets`:自动化删除推文的新工具
下一篇:如何在Lottie React Native中动态改变动画颜色:完整指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/21 17:44:54

Agent反射与自我纠错主动优化

一、什么是 AI Reflexion 反射机制Reflexion 反射&#xff0c;就是给 AI Agent 增加一套「自我复盘系统」。在任务完成后、结果交付前&#xff0c;让 AI跳出原有任务逻辑&#xff0c;以第三方审核者的身份&#xff0c;重新审视自己的全过程&#xff1a;我的任务理解是否准确&am…

作者头像 李华
网站建设 2026/10/21 19:45:57

一张照片生成 3D 衣服,为什么总在“重新打光“那一刻露馅?

&#x1f30a; 专注 AI 大模型与前沿科技深度解析&#xff0c;习惯从工程师视角拆解技术热点&#xff0c;让我们一起在技术浪潮中保持清醒与好奇 &#x1f680;一张照片生成 3D 衣服&#xff0c;为什么总在"重新打光"那一刻露馅&#xff1f; 上个月帮一个做独立游戏的…

作者头像 李华
网站建设 2026/10/21 19:45:58

ESP8266振动监测实战:SW-420传感器数据上报KiwisIoT

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/21 19:45:58

Java Swing实现捕鱼达人:核心机制、游戏循环与避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/21 19:45:58

FloEFD流域识别失败?3大高频坑与系统排查法

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华