Medusa Notification 模块演进解析:从 v2.0 到 v2.20 的核心能力与实现原理
2026/9/11 5:27:10 网站建设 项目流程

Medusa Notification 模块演进解析:从 v2.0 到 v2.20 的核心能力与实现原理

【免费下载链接】medusaThe world's most flexible commerce platform for agents and developers项目地址: https://gitcode.com/GitHub_Trending/me/medusa

Medusa 的 Notification(通知)模块负责将订单、客户、库存等业务事件以邮件、短信等渠道推送给用户,是@medusajs/notification包的核心载体。本文以该包 CHANGELOG.md 的版本演进为主线,结合packages/modules/notification目录下的模型、服务、加载器与内置提供者源码,梳理模块在 Medusa 2.0 大版本下的数据模型变化、提供者(Provider)插件体系、幂等发送流程以及底层基础设施升级,帮助你理解该模块的架构设计,并掌握在 medusa-config 中配置通知提供者的方法。

模块定位与包结构

在 Medusa 2.x 中,Notification 是一个独立模块(Module),通过Module(Modules.NOTIFICATION, ...)在 src/index.ts 中声明,由NotificationModuleService提供服务、loadProviders负责加载配置中的提供者。包结构清晰分层:

  • src/models/notificationnotification-provider两个 MikroORM 实体;
  • src/services/:模块主服务与提供者内部服务;
  • src/loaders/:提供者注册与数据库同步逻辑;
  • src/providers/:内置的 Medusa Cloud Email 提供者;
  • integration-tests/:模块服务的单元与集成测试。

从 package.json 可见,当前版本为2.20.1,要求 Node.js>=20,并以@medusajs/framework(同为2.20.1)作为 peer dependency,这也解释了 CHANGELOG 中大量Updated dependencies条目——模块的功能始终紧随框架同步演进。

数据模型演进:notification 实体的字段补全

CHANGELOG 中最具业务价值的变化集中在 v2.12.0(对应 src/models/notification.ts):

  • PR #14104:为 notification 模型新增provider_data字段;
  • PR #14102:为 notification 模型新增from字段。

这两个字段的加入补齐了通知场景的关键诉求:

  • frommodel.text().searchable().nullable(),标识发送方(可以是邮箱、电话号码或用户名,取决于渠道),解决"以谁的名义发送"的问题;
  • provider_datamodel.json().nullable(),存放渠道或提供者特有的附加数据,例如邮件中的cc/bcc列表。

结合 medusa-cloud-email.ts 的send实现可见,fromprovider_datatotemplatedataattachmentscontent一起被完整透传给提供者端点,是发送请求体的一部分。

完整的 notification 实体还包含以下关键字段(均在 src/models/notification.ts 中定义):

字段类型说明
idmodel.id({ prefix: "noti" })主键,前缀noti
totext,searchable接收方,依渠道而定
fromtext,searchable,nullable发送方(v2.12.0 新增)
channeltext渠道,如email
templatetext,nullable提供者系统中的模板名,v2.11.2 起允许为空
datajson,nullable传给提供者渲染通知的数据
provider_datajson,nullable渠道/提供者附加数据(v2.12.0 新增)
trigger_typetext,nullable触发来源(事件名、工作流等)
resource_idtext,searchable,nullable关联资源 ID,便于 UI 展示
resource_typetext,nullable关联资源类型,如order
receiver_idtext,index,nullable接收者 ID(客户、用户等)
original_notification_idtext,nullable重试时指向原始通知
idempotency_keytext,unique,nullable幂等键,防重发
external_idtext,nullable外部系统中的通知 ID
statusenum,默认pending发送状态

其中status枚举定义在 packages/core/utils/src/notification/common.ts:pendingsuccessfailure三态,是幂等重试逻辑的判断基础。实体级注释也点明设计意图:每个条目应当有 TTL,以避免数据库膨胀并满足 GDPR 的留存要求。

此外,CHANGELOG v2.11.2 中"Make template nullable on emails"(PR #13889)将template字段改为可空,允许不依赖外部模板系统、直接以content发送纯内容型通知,与 Cloud Email 提供者的content参数设计相互印证。

提供者(Provider)插件体系与 Medusa Cloud Email

CHANGELOG v2.11.2 中 PR #13781 新增了 Medusa Cloud Email 提供者,这是模块内置的唯一默认提供者,实现在 src/providers/medusa-cloud-email.ts。它继承AbstractNotificationProviderService,在send中向{endpoint}/send发起fetchPOST 请求:

  • 请求头携带Authorization: Basic <api_key>
  • 配置了sandbox_handle时附加x-medusa-sandbox-handle头(对应 v2.11.2 中"Inject sandbox handle in cloud config"的变更);
  • 配置了environment_handle时附加x-medusa-environment-handle头;
  • 请求体透传tofromattachmentstemplatedataprovider_datacontent,返回外部通知 ID。

自动注册逻辑

src/loaders/providers.ts 展示了提供者的加载流程:

  1. 检查配置中是否已有覆盖email渠道的提供者;
  2. 若没有,且cloud配置通过validateCloudOptions校验(要求提供api_keyendpoint,且environment_handlesandbox_handle至少其一),则自动注册cloud提供者并追加到 providers 列表;
  3. 调用moduleProviderLoader注册所有自定义提供者;
  4. 通过syncDatabaseProviders将 providers 同步进notification_provider表。

提供者配置与校验

模块选项类型NotificationModuleOptions定义在 src/types/index.ts,支持:

  • providers[]:每项包含resolve(模块提供者导出或路径)、id(唯一标识)、options(传给提供者构造器的键值对,channels数组声明支持的渠道);
  • cloud:Medusa Cloud Email 选项(api_keyendpointenvironment_handle?sandbox_handle?)。

syncDatabaseProviders的要点:

  • 每个 provider 必须提供id,否则抛错;
  • 通过validateProviders校验同一渠道不能配置多个提供者(重复配置同一channel会直接抛错);
  • 数据库中已存在但配置中不再出现的提供者会被自动禁用(is_enabled = false),而非删除。

对应的notification_provider实体(src/models/notification-provider.ts)字段包括handlenameis_enabled(默认 true)、channels(数组)以及与通知的一对多关系。

提供者内存缓存与渠道路由

src/services/notification-provider.ts 是提供者的内部服务:

  • getProviderForChannels首次调用时按is_enabled: true查询数据库,构建"渠道 → 提供者"的内存 Map(因为提供者只在启动时注册、运行期不变,可安全缓存);
  • send通过retrieveProviderRegistration从 Awilix 容器中按np_<providerId>前缀(NotificationProviderRegistrationPrefix)解析提供者实例,调用其send,解析失败时会给出"请检查项目配置文件"的明确错误提示。

核心发送流程:幂等、去重与状态回写

模块主服务 src/services/notification-module-service.ts 的createNotifications是发送入口,其内部createNotifications_展示了完整的工程化设计:

  1. 幂等键查重:收集所有idempotency_key,在同一事务内查询已存在记录,构建existsMap
  2. 过滤待处理项:只有"无幂等键"或"已存在但状态为failure"的通知才会进入发送队列——失败重试不会产生重复记录;
  3. 渠道路由:按channel调用getProviderForChannels匹配提供者,生成noti前缀的 ID 并写入provider_id
  4. 事务内预创建:先行create通知记录,源码注释明确说明这是"为防止并发操作列出同一批通知";
  5. 并发发送promiseAll并行发送,发送成功则回写external_idstatus = success;提供者缺失、未启用或发送异常时置status = failure并抛出对应MedusaErrorNOT_FOUNDUNEXPECTED_STATE);
  6. finally 统一回写:无论成败都update状态,并按原顺序重组结果返回。

发送失败的典型错误信息(源码中可复现):

  • Could not find a notification provider for channel: <channel> for notification id <id>——未配置对应渠道的提供者;
  • Notification provider <id> is not enabled. To enable it, configure it as a provider in the notification module options.——提供者被禁用。

这一流程与 v2.10.2 中"Module Internal Events"(PR #13296)带来的@EmitEvents()装饰器配合,可在发送前后向事件总线广播模块内部事件,供订阅者扩展。

版本演进时间线与工程化治理

除上述业务功能外,CHANGELOG 还记录了模块在工程化层面的演进,可按主题归纳如下:

版本变更类型核心内容
2.0.0Major随 Medusa 2.0 发布,模块化架构落地
2.4.0Minor/Patch升级至 MikroORM 6;修复唯一约束需考虑软删除记录的问题
2.5.0PatchAbstractModuleService的 create 方法类型安全化
2.6.1Patch移除 Medusa 各包上的版本范围限制
2.10.2Patch支持模块内部事件
2.11.2Patch新增 Medusa Cloud Email 提供者;邮件模板可空;云配置注入 sandbox handle
2.11.3Patch依赖清理与改进
2.12.0Patch模型新增provider_datafrom字段
2.12.5Patchmedusa 配置支持模块选项自动补全
2.13.0Minor常规 minor 版本升级
2.17.2Patch补充包 bugs 元数据
2.20.xPatch跟随@medusajs/framework同步更新

几个值得注意的底层变化:

  • MikroORM 6 升级(v2.4.0,PR #10292):模块的实体定义、迁移文件与mikro-orm.config.dev.ts均基于新版本构建,migrations/目录下的多个迁移文件(Migration20240509083918_InitialSetupMigration等)记录了表结构随版本演进的轨迹;
  • 唯一约束与软删除(v2.4.0,PR #11048):修复唯一约束需将软删除记录纳入考虑,保证idempotency_key等唯一字段在软删除场景下不冲突;
  • 模块配置自动补全(v2.12.5,PR #14465)NotificationModuleOptions通过模块声明合并进入@medusajs/typesModuleOptions接口(见 src/types/index.ts),使 medusa-config 中编写@medusajs/notification选项时获得 IDE 类型提示;
  • 依赖治理(v2.11.3、v2.6.1):peer 依赖收敛到@medusajs/framework单一包并重新导出(v2.11.0,PR #13439),同时移除包间版本范围,降低依赖解析复杂度。

典型配置示例与验证路径

在 medusa-config 中配置 Notification 模块的方式如下(字段均对应NotificationModuleOptions类型):

module.exports = defineConfig({ modules: [ { resolve: "@medusajs/notification", options: { providers: [ { resolve: "@medusajs/notification-sendgrid", id: "sendgrid", options: { channels: ["email"], // 提供者所需的其他选项 api_key: process.env.SENDGRID_API_KEY, from: process.env.SENDFROM_EMAIL, }, }, ], // 或使用内置的 Medusa Cloud Email: // cloud: { // api_key: process.env.MEDUSA_CLOUD_API_KEY, // endpoint: "https://notification.medusajs.com", // environment_handle: process.env.MEDUSA_ENV_HANDLE, // sandbox_handle: process.env.MEDUSA_SANDBOX_HANDLE, // }, }, }, ], })

需要注意的约束:

  • 同一channel只能配置一个提供者,重复配置会在启动时抛错;
  • 若配置了覆盖email渠道的自定义提供者,Medusa Cloud Email 不会自动注册;
  • 未配置任何提供者却发起发送,通知会以failure状态落库并抛出NOT_FOUND错误。

模块的集成测试集中在 integration-tests/tests/notification-module-service/(含默认提供者与 Medusa Cloud Email 两条测试线),通过yarn test:integration运行(见 package.json 的 scripts),可用于验证上述发送流程与幂等行为。

结语

从 v2.0 到 v2.20,@medusajs/notification的 CHANGELOG 记录了一条清晰的演进路径:数据模型层面补全了fromprovider_data,提供者层面引入了内置的 Medusa Cloud Email 并建立"渠道唯一"的注册与校验机制,底层则随框架完成 MikroORM 6 升级、内部事件与类型安全化改造。理解这些版本变更背后的源码实现,可以帮助你在自建提供者、配置多渠道通知或排查发送失败时快速定位问题所在。

【免费下载链接】medusaThe world's most flexible commerce platform for agents and developers项目地址: https://gitcode.com/GitHub_Trending/me/medusa

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询