Files
junhong_cmp_fiber/openspec/specs/worker-role-management/spec.md
huang 3a2e3f2571
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m8s
浅浅升级一下
2026-05-06 14:41:14 +08:00

131 lines
5.4 KiB
Markdown
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.
# worker-role-management Specification
## Purpose
TBD - created by archiving change split-worker-roles. Update Purpose after archive.
## Requirements
### Requirement: Worker 角色配置
系统 SHALL 支持 `all``leader``consumer` 三种 Worker 运行角色,并在启动时根据配置决定当前进程职责。角色值 MUST 使用小写英文字符串,非法角色 MUST 使配置加载失败并返回明确错误。
#### Scenario: 默认兼容模式
- **WHEN** 未设置 `JUNHONG_WORKER_ROLE`
- **THEN** Worker 使用默认角色 `all`
- **AND** 启动行为与变更前单实例 worker 保持一致
#### Scenario: 非法角色启动失败
- **WHEN** 设置 `JUNHONG_WORKER_ROLE=scheduler`
- **THEN** `config.Load()` 返回配置校验错误
- **AND** Worker 不进入 Redis、PostgreSQL 或 Asynq 启动流程
#### Scenario: 实例名称可为空
- **WHEN** 未设置 `JUNHONG_WORKER_INSTANCE_NAME`
- **THEN** Worker 可以正常启动
- **AND** 启动日志中的实例名称为空或显示默认占位值
### Requirement: 按角色启停 Worker 模块
系统 SHALL 将 Worker 启动流程拆分为共享依赖初始化和角色模块启停两部分。所有角色 MUST 启动 Asynq Worker Server只有 `all``leader` SHALL 启动主动调度与初始化模块。
**共享模块**
- Redis 客户端
- PostgreSQL 连接
- Storage 服务(可选)
- Gateway 客户端(可选)
- Asynq Client
- `BootstrapWorker`
- Asynq Worker Server
- `PollingConfigManager`
- `PollingQueueManager`
- `PollingBase`
- `PollingLifecycleService`
- TaskHandler 及全部任务 Handler 注册
**单例模块**
- `PollingInitializer`
- `PollingScheduler`
- Asynq Scheduler
#### Scenario: all 角色启动全部模块
- **WHEN** `worker.role=all`
- **THEN** Worker 启动 Asynq Worker Server
- **AND** 启动 `PollingInitializer`
- **AND** 启动 `PollingScheduler`
- **AND** 启动 Asynq Scheduler
#### Scenario: leader 角色启动全部模块
- **WHEN** `worker.role=leader`
- **THEN** Worker 启动 Asynq Worker Server
- **AND** 启动 `PollingInitializer`
- **AND** 启动 `PollingScheduler`
- **AND** 启动 Asynq Scheduler
- **AND** 日志表达该实例承担单例主动调度职责
#### Scenario: consumer 角色只启动任务消费模块
- **WHEN** `worker.role=consumer`
- **THEN** Worker 启动 Asynq Worker Server
- **AND** 注册全部任务 Handler
- **AND** 不启动 `PollingInitializer`
- **AND** 不启动 `PollingScheduler`
- **AND** 不启动 Asynq Scheduler
### Requirement: consumer 保留轮询任务运行依赖
`consumer` 角色虽然不主动调度,但系统 SHALL 保留轮询任务 Handler 所需依赖,使其可以正常消费 Leader 投递的轮询任务并在任务完成后重新入队。
#### Scenario: consumer 消费轮询任务后可重新入队
- **WHEN** `consumer` 实例消费 `TaskTypePollingCarddata` 任务
- **THEN** Handler 可通过 `PollingBase` 读取轮询配置和 Redis 并发控制
- **AND** Handler 可通过 `PollingQueueManager` 将卡重新写回分片 Sorted Set
#### Scenario: consumer 可处理导入任务的轮询生命周期回调
- **WHEN** `consumer` 实例消费 IoT 卡导入任务并创建新卡
- **THEN** 导入任务可通过 `PollingLifecycleService` 将新卡按配置加入轮询分片队列
- **AND** 该操作不依赖本实例启动 `PollingScheduler`
### Requirement: Worker 启动日志
系统 SHALL 在 Worker 启动时输出当前角色、实例名称、启用模块和禁用模块,日志消息 MUST 使用中文,便于部署后通过日志确认实际运行职责。
#### Scenario: consumer 日志显示禁用单例模块
- **WHEN** `worker.role=consumer`
- **THEN** 启动日志包含 `Worker 角色`
- **AND** 启动日志包含 `实例名称`
- **AND** 启动日志显示已禁用 `polling_initializer``polling_scheduler``asynq_scheduler`
#### Scenario: leader 日志显示启用单例模块
- **WHEN** `worker.role=leader`
- **THEN** 启动日志显示已启用 `queue_server``polling_initializer``polling_scheduler``asynq_scheduler`
### Requirement: 按启动状态优雅关闭
系统 SHALL 只关闭当前角色实际启动过的后台模块,避免 `consumer` 对未启动模块执行 `Stop``Shutdown`
#### Scenario: consumer 关闭不访问未启动调度器
- **WHEN** `consumer` 收到退出信号
- **THEN** Worker 关闭 Asynq Worker Server
- **AND** 不调用未启动的 `PollingScheduler.Stop`
- **AND** 不调用未启动的 Asynq Scheduler `Shutdown`
#### Scenario: leader 关闭全部已启动模块
- **WHEN** `leader` 收到退出信号
- **THEN** Worker 关闭 Asynq Scheduler
- **AND** 停止 `PollingScheduler`
- **AND** 优雅关闭 Asynq Worker Server
### Requirement: 多实例部署语义
系统 SHALL 支持“1 个 `leader` + N 个 `consumer`”的部署形态。部署时 SHOULD 固定只有一个 `leader``all` 实例承担主动调度职责,横向扩容 SHALL 优先增加 `consumer`
#### Scenario: 新增 consumer 不复制主动调度
- **WHEN** 生产已有一个 `leader`,再新增一个 `consumer`
- **THEN** 定时任务仍只由 `leader` 主动提交
- **AND** 轮询全量初始化仍只由 `leader` 执行
- **AND** `consumer` 只从 Asynq 队列消费已有任务
#### Scenario: 回滚到单实例兼容模式
- **WHEN** 多实例部署出现问题并停止所有 `consumer`
- **THEN** 保留一个 `leader` 可继续运行完整 Worker 功能
- **AND** 必要时可将唯一实例配置切回 `all` 恢复兼容模式