Worker 当前架构与演进边界
BeeX 已经完成运行形态拆分。业务代码仍由同一套
beex-service 构建,但在部署时通过 SEAHUB_SERVICE_ROLE 分成 api、wa、worker、webhook 四个独立进程;只有 worker 开启 Spring Scheduling。本文记录当前事实,不再把已完成的拆分写成未来计划。1. 当前结论
api · 7002
App/H5 用户接口,不运行定时任务。
对外服务wa · 7010
WhatsApp 登录、消息与机器人链路,不运行定时任务。
消息入口worker · 7020
订单同步、结算、清理、刷新与推送调度。
唯一调度进程webhook · 7030
Xendit、平台和其他第三方回调,不运行定时任务。
回调入口已落地:四个角色拥有独立应用名、端口、systemd/JAR 和云效流水线;生产 worker 无公网业务入口。管理后台是独立仓库
beex-admin-service,不属于这四个角色。2. 运行角色和流量边界
flowchart LR
CLIENT["App / H5"] --> ALB["ALB / Nginx"]
META["Meta WhatsApp"] --> ALB
THIRD["Xendit / TikTok / Shopee / Feishu"] --> ALB
ALB -->|"/api/**"| API["api :7002"]
ALB -->|"/webhooks/whatsapp"| WA["wa :7010"]
ALB -->|"其他 /webhooks/**"| WEBHOOK["webhook :7030"]
WORKER["worker :7020"] --> DB[("MySQL")]
WORKER --> REDIS[("Redis Lock")]
WORKER --> PLATFORM["第三方平台 API"]
API --> DB
WA --> DB
WEBHOOK --> DB
| 角色 | Spring profile / 默认角色 | Scheduling | HTTP 原则 |
|---|---|---|---|
api | application-api.properties | 关闭 | 仅开放用户业务接口和健康检查。 |
wa | application-wa.properties | 关闭 | 仅开放 WhatsApp 所需路径。 |
worker | application-worker.properties | 开启 | 不承接外部业务流量,只保留健康与受控诊断。 |
webhook | application-webhook.properties | 关闭 | 只开放指定第三方回调路径。 |
ServiceRoleHttpFilter 按角色限制 HTTP 路径;不允许通过“部署了同一个 JAR”推断每个进程都能处理所有接口。
3. 当前定时任务清单
当前代码共 13 个 @Scheduled 入口。频率均可由环境变量覆盖,表中为代码默认值。
| 任务 | 默认周期 | 主要写入/影响 | 风险级别 |
|---|---|---|---|
| TikTok CAP 订单同步 | 15 分钟 | 订单、归因、佣金、活动权益 | 资金高风险 |
| TikTok Creator 订单同步 | 15 分钟 | 订单、归因、佣金、活动权益 | 资金高风险 |
| Shopee Conversion 同步 | 15 分钟 | 订单、归因、佣金、活动权益 | 资金高风险 |
| Lazada Conversion 同步 | 15 分钟 | 订单、归因、佣金、活动权益 | 资金高风险 |
| Traveloka 订单同步 | 15 分钟 | 订单、归因、佣金 | 资金高风险 |
| 佣金到期释放 | 5 分钟 | 佣金状态、钱包账本 | 资金高风险 |
| Xendit 余额不足提现重试 | 10 分钟 | 提现单、冻结/解冻余额 | 资金高风险 |
| Push 消息派发 | 5 秒 | 推送任务状态、APNs/FCM | 中 |
| 优惠券过期扫描 | 5 分钟 | 用户券状态 | 中 |
| TikTok Partner Campaign 商品同步 | 30 分钟 | 高返佣商品缓存 | 中 |
| TikTok 授权账号 Token 刷新 | 60 分钟 | 平台授权账号 | 高 |
| App Store 版本同步 | 60 分钟 | Native 版本配置 | 低 |
| Ops 监控刷新 | 60 秒 | 监控快照与告警 | 低 |
邀请绑定:识别到分享人即直接建立一层邀请关系,WhatsApp JOIN 流程调用
userRepository.bindInviterIfAbsent + growthRepository.bindRelation,与 GrowthController.bind() 同一套逻辑。4. 调度开关
ServiceSchedulingEnabledCondition 是调度的唯一总门禁:
- 如果配置了
seahub.scheduling.enabled,以该布尔值为准。 - 没有显式配置时,仅
role=worker或role=all开启。 - api、wa、webhook 的环境配置显式设为
false;worker 显式设为true。
部署约束:生产禁止使用
role=all。它只适合本地兼容启动,否则会重新造成 API 实例跑定时任务。5. 锁、幂等与游标
| 机制 | 当前要求 | 验收方式 |
|---|---|---|
| 分布式任务锁 | 多 worker 实例只能有一个实例执行同一批任务;TTL 必须覆盖正常执行时间并支持失败释放。 | 并行启动两个 worker,确认同一锁窗口只有一条执行记录。 |
| 平台订单幂等 | 平台订单号/明细号建立唯一约束;重复拉取只能更新状态,不能重复创建佣金。 | 对同一时间窗重复同步两次,订单数和钱包账本不增加。 |
| 佣金与钱包幂等 | 佣金记录、权益预占和钱包 ledger 使用稳定业务幂等键。 | 重放订单状态回调,用户余额只变化一次。 |
| 同步游标与回看窗 | 保存平台游标,同时保留重叠回看时间窗,避免边界订单丢失。 | 模拟任务中断后恢复,边界订单仍能补齐。 |
| 失败可重试 | 区分临时错误和永久错误;记录 requestId、平台错误码、重试次数与下一次时间。 | 第三方 5xx 恢复后任务自动成功,4xx 不无限重试。 |
6. 部署与发布
测试和生产均使用独立流水线发布四个角色,同一 commit 可以分别构建和部署。真实机器、流水线 ID、ALB 路由和 systemd 路径以 部署总览 为唯一来源,本文件不复制易漂移的基础设施明细。
sequenceDiagram
participant G as Git Commit
participant P as Yunxiao Pipeline
participant A as Artifact
participant E as ECS Role Instance
participant H as Health Check
G->>P: 选择同一 commit
P->>A: Maven 构建并生成制品
P->>E: 按 api/wa/worker/webhook 发布
E->>H: 角色、端口、健康检查
H-->>P: 成功或自动失败
任何修改都必须走对应云效流水线;不以手工复制 JAR 或 SSH 启动作为正式发布方式。
7. 监控与告警
- 每个同步任务记录:开始时间、结束时间、扫描范围、拉取数、新增数、更新数、失败数、平台 requestId。
- 核心指标:最后成功时间、连续失败次数、同步延迟、订单未归因率、佣金生成失败数、锁等待时间。
- 订单同步超过两个正常周期未成功、资金任务发生异常、Token 即将过期时必须通知飞书。
- 告警消息显示环境、国家、任务名、代码版本和可定位的 trace/requestId,不能只写“任务失败”。
8. MQ 演进条件
当前核心模式仍是 Worker 定时拉取 + 数据库事务 + 分布式锁。§3 里标"中/低"风险的 5 个非资金任务已经启动 Outbox + RocketMQ 迁移(不等触发条件,现在就做,理由、采购决策和方案见 Outbox + RocketMQ 接入技术方案)。资金相关的 7 个任务不在这次范围内,继续按下面的触发条件评估是否需要接入:
- 订单后处理耗时显著拖慢平台同步游标推进。
- 佣金、活动、通知、BI 需要独立重试和独立扩容。
- 单任务批次持续超过调度周期,或 DB 扫描成为瓶颈。
- 需要可回放的业务事件审计,而数据库任务表已不足以支撑。
flowchart LR
SYNC["平台订单同步"] --> DB["订单事务落库"]
DB --> OUTBOX["Outbox 事件"]
OUTBOX --> MQ["RocketMQ(Phase 1 非资金任务已启动, 资金路径触发后再评估)"]
MQ --> REWARD["佣金/活动消费者"]
MQ --> NOTICE["通知消费者"]
MQ --> BI["BI/埋点消费者"]
演进顺序固定为:先落 Outbox,再发布消息;消费者使用业务幂等键。禁止在数据库事务提交前直接发消息。
非资金任务的具体技术方案:见 Outbox + RocketMQ 接入技术方案——阿里云 RocketMQ 在雅加达没有 Serverless 可用区,只能买标准版/专业版,年付 ≈¥17,000,已确认接受该成本按此采购;同时做了可替换的发布/订阅接口设计,以后 broker 要再换只改实现类。
9. 运维验收清单
- api、wa、webhook 日志中不出现定时任务执行记录。
- worker 日志显示
role=worker且调度开启,但外部业务路径返回 404。 - 双 worker 部署时,同一任务不会重复生成订单、佣金、钱包账本或通知。
- 任一角色单独发布不会覆盖其他角色 JAR,也不会重启其他角色。
- 任务连续失败、订单延迟和授权过期均有飞书告警。
- 测试验证后,生产用同一 commit 分角色发布,并记录发布人与版本。