feat(task): 新增定时任务控制系统与分享码配置

- 增加设备持久化、阻抗数据持久化、分享码持久化定时任务
- 通过环境变量 ENABLE_PERSIST_TASK 和 ENABLE_IMPEDANCE_PERSIST_TASK 控制任务启用
- 分享码配置新增最大数量和TTL时间支持多种时间单位(m/h/d)
- 实现任务批量处理、锁机制及失败重试保障数据一致性
- 定时任务启动集成至服务主流程,增强系统可配置性和运维便利性

feat(ota): 新增根据设备型号和版本号查询版本名称接口

- 实现 GET /audio/getVerName 接口返回唯一 OTA 版本名称 verName
- 添加请求参数校验及错误处理逻辑
- 在仓库层新增按型号和版本号查询版本名称的方法
- 完善接口文档及Swagger定义,支持前端调用查询版本名称功能
This commit is contained in:
eafonyang
2026-09-02 11:13:14 +08:00
parent ceea657ccf
commit dd92845bc2
8 changed files with 273 additions and 21 deletions
+83 -20
View File
@@ -12,10 +12,14 @@
- [internal/config/equalize.go](file://internal/config/equalize.go) - [internal/config/equalize.go](file://internal/config/equalize.go)
- [internal/database/mysql.go](file://internal/database/mysql.go) - [internal/database/mysql.go](file://internal/database/mysql.go)
- [internal/cache/redis.go](file://internal/cache/redis.go) - [internal/cache/redis.go](file://internal/cache/redis.go)
- [internal/cache/share_code_cache.go](file://internal/cache/share_code_cache.go)
- [internal/search/meilisearch.go](file://internal/search/meilisearch.go) - [internal/search/meilisearch.go](file://internal/search/meilisearch.go)
- [internal/router/router.go](file://internal/router/router.go) - [internal/router/router.go](file://internal/router/router.go)
- [internal/middleware/cors.go](file://internal/middleware/cors.go) - [internal/middleware/cors.go](file://internal/middleware/cors.go)
- [internal/middleware/logger.go](file://internal/middleware/logger.go) - [internal/middleware/logger.go](file://internal/middleware/logger.go)
- [internal/task/device_persist.go](file://internal/task/device_persist.go)
- [internal/task/impedance_persist.go](file://internal/task/impedance_persist.go)
- [internal/task/share_code_persist.go](file://internal/task/share_code_persist.go)
- [pkg/logger/logger.go](file://pkg/logger/logger.go) - [pkg/logger/logger.go](file://pkg/logger/logger.go)
- [Makefile](file://Makefile) - [Makefile](file://Makefile)
- [Dockerfile.multistage](file://Dockerfile.multistage) - [Dockerfile.multistage](file://Dockerfile.multistage)
@@ -31,9 +35,10 @@
## 更新摘要 ## 更新摘要
**变更内容** **变更内容**
- 配置管理系统重大重构:移除所有硬编码的环境特定值,完全转向环境变量驱动 - 配置管理系统重大重构:移除所有硬编码的环境特定值,完全转向环境变量驱动
- 更新环境变量配置说明,强调纯环境变量配置的最佳实践 - 新增定时任务控制变量:ENABLE_PERSIST_TASK、ENABLE_IMPEDANCE_PERSIST_TASK
- 移除生产环境特定的硬编码值描述,统一使用环境变量管理 - 增强分享码配置:SHARE_CODE_MAX_PER_MAC、SHARE_CODE_TTL_MIN(支持多种时间单位格式)
- 增强配置验证机制,确保所有必要的环境变量在生产环境中正确设置 - 完善配置验证机制:对数据库、Meilisearch、Redis、均衡器、S3配置进行全面校验
- 统一环境管理:通过环境变量实现真正的配置外置化和环境隔离
## 目录 ## 目录
1. [简介](#简介) 1. [简介](#简介)
@@ -55,10 +60,11 @@
- cmd/server:应用入口,负责初始化配置、连接数据库与缓存、启动 HTTP 服务器、优雅关闭 - cmd/server:应用入口,负责初始化配置、连接数据库与缓存、启动 HTTP 服务器、优雅关闭
- internal/config:集中加载与校验环境变量,生成运行所需配置,支持S3、均衡器等新配置 - internal/config:集中加载与校验环境变量,生成运行所需配置,支持S3、均衡器等新配置
- internal/databaseMySQL 连接与连接池配置 - internal/databaseMySQL 连接与连接池配置
- internal/cacheRedis 客户端初始化 - internal/cacheRedis 客户端初始化及分享码缓存管理
- internal/searchMeilisearch 客户端初始化与检索封装 - internal/searchMeilisearch 客户端初始化与检索封装
- internal/router:路由注册与中间件装配 - internal/router:路由注册与中间件装配
- internal/middlewareCORS、请求日志、请求 ID 等中间件 - internal/middlewareCORS、请求日志、请求 ID 等中间件
- internal/task:定时任务处理(设备持久化、阻抗数据持久化、分享码持久化)
- pkg/loggerZap 日志配置(开发/生产差异化) - pkg/loggerZap 日志配置(开发/生产差异化)
- Makefile:增强的构建与测试命令,支持跨平台编译和Swagger文档生成 - Makefile:增强的构建与测试命令,支持跨平台编译和Swagger文档生成
- Dockerfile.multistage:多阶段Docker构建配置 - Dockerfile.multistage:多阶段Docker构建配置
@@ -76,6 +82,7 @@ MW_CORS["internal/middleware/cors.go"]
MW_LOGGER["internal/middleware/logger.go"] MW_LOGGER["internal/middleware/logger.go"]
CFG["internal/config/config.go"] CFG["internal/config/config.go"]
LOGPKG["pkg/logger/logger.go"] LOGPKG["pkg/logger/logger.go"]
TASK["internal/task/*"]
end end
subgraph "外部服务" subgraph "外部服务"
MYSQL["MySQL 数据库"] MYSQL["MySQL 数据库"]
@@ -99,6 +106,7 @@ end
MAIN --> CFG MAIN --> CFG
MAIN --> LOGPKG MAIN --> LOGPKG
MAIN --> ROUTER MAIN --> ROUTER
MAIN --> TASK
ROUTER --> MW_CORS ROUTER --> MW_CORS
ROUTER --> MW_LOGGER ROUTER --> MW_LOGGER
MAIN --> MYSQL MAIN --> MYSQL
@@ -115,12 +123,15 @@ ENV --> MAIN
``` ```
**图表来源** **图表来源**
- [cmd/server/main.go:1-201](file://cmd/server/main.go#L1-L201) - [cmd/server/main.go:1-209](file://cmd/server/main.go#L1-L209)
- [internal/router/router.go:14-41](file://internal/router/router.go#L14-L41) - [internal/router/router.go:14-41](file://internal/router/router.go#L14-L41)
- [internal/middleware/cors.go:7-19](file://internal/middleware/cors.go#L7-L19) - [internal/middleware/cors.go:7-19](file://internal/middleware/cors.go#L7-L19)
- [internal/middleware/logger.go:10-45](file://internal/middleware/logger.go#L10-L45) - [internal/middleware/logger.go:10-45](file://internal/middleware/logger.go#L10-L45)
- [internal/config/config.go:18-95](file://internal/config/config.go#L18-L95) - [internal/config/config.go:18-95](file://internal/config/config.go#L18-L95)
- [pkg/logger/logger.go:8-19](file://pkg/logger/logger.go#L8-L19) - [pkg/logger/logger.go:8-19](file://pkg/logger/logger.go#L8-L19)
- [internal/task/device_persist.go:24-35](file://internal/task/device_persist.go#L24-L35)
- [internal/task/impedance_persist.go:30-41](file://internal/task/impedance_persist.go#L30-L41)
- [internal/task/share_code_persist.go:24-34](file://internal/task/share_code_persist.go#L24-L34)
- [Dockerfile.multistage:1-26](file://Dockerfile.multistage#L1-L26) - [Dockerfile.multistage:1-26](file://Dockerfile.multistage#L1-L26)
- [docker-compose.yml:1-33](file://docker-compose.yml#L1-L33) - [docker-compose.yml:1-33](file://docker-compose.yml#L1-L33)
- [scripts/deploy.sh:1-134](file://scripts/deploy.sh#L1-L134) - [scripts/deploy.sh:1-134](file://scripts/deploy.sh#L1-L134)
@@ -134,6 +145,8 @@ ENV --> MAIN
## 核心组件 ## 核心组件
- **重构后的配置加载与校验**:集中于 config 包,完全基于环境变量加载配置,对所有必要参数进行严格校验 - **重构后的配置加载与校验**:集中于 config 包,完全基于环境变量加载配置,对所有必要参数进行严格校验
- **增强的定时任务系统**:支持设备和分享码的定时持久化,通过环境变量控制启用状态
- **灵活的分享码配置**:支持最大数量限制和TTL时间配置,支持多种时间单位格式(m、h、d)
- 数据库连接:使用 MySQL 驱动,配置连接池参数并在启动时进行连通性校验 - 数据库连接:使用 MySQL 驱动,配置连接池参数并在启动时进行连通性校验
- 缓存连接:Redis 客户端初始化,支持主机、端口、密码、库号 - 缓存连接:Redis 客户端初始化,支持主机、端口、密码、库号
- 搜索服务:Meilisearch 客户端初始化,提供模型列表检索能力 - 搜索服务:Meilisearch 客户端初始化,提供模型列表检索能力
@@ -141,8 +154,6 @@ ENV --> MAIN
- 均衡器API:支持内外网切换的均衡器接口配置 - 均衡器API:支持内外网切换的均衡器接口配置
- 路由与中间件:Gin 路由注册,内置 CORS、请求日志、请求 ID、恢复中间件 - 路由与中间件:Gin 路由注册,内置 CORS、请求日志、请求 ID、恢复中间件
- 日志:Zap 生产/开发差异化配置,按状态输出不同级别日志 - 日志:Zap 生产/开发差异化配置,按状态输出不同级别日志
- 定时任务:支持设备和分享码的定时持久化任务
- 分享码配置:支持最大数量和TTL时间配置
- 部署脚本自动化:支持本地交叉编译、远程部署、容器重启等完整流程 - 部署脚本自动化:支持本地交叉编译、远程部署、容器重启等完整流程
- 批量代码同步:支持增量同步和虚拟执行预览 - 批量代码同步:支持增量同步和虚拟执行预览
- 多阶段Docker构建:支持跨平台编译和镜像优化 - 多阶段Docker构建:支持跨平台编译和镜像优化
@@ -162,6 +173,9 @@ ENV --> MAIN
- [internal/middleware/cors.go:7-19](file://internal/middleware/cors.go#L7-L19) - [internal/middleware/cors.go:7-19](file://internal/middleware/cors.go#L7-L19)
- [internal/middleware/logger.go:10-45](file://internal/middleware/logger.go#L10-L45) - [internal/middleware/logger.go:10-45](file://internal/middleware/logger.go#L10-L45)
- [pkg/logger/logger.go:8-19](file://pkg/logger/logger.go#L8-L19) - [pkg/logger/logger.go:8-19](file://pkg/logger/logger.go#L8-L19)
- [internal/task/device_persist.go:24-35](file://internal/task/device_persist.go#L24-L35)
- [internal/task/impedance_persist.go:30-41](file://internal/task/impedance_persist.go#L30-L41)
- [internal/task/share_code_persist.go:24-34](file://internal/task/share_code_persist.go#L24-L34)
- [scripts/deploy.sh:1-134](file://scripts/deploy.sh#L1-L134) - [scripts/deploy.sh:1-134](file://scripts/deploy.sh#L1-L134)
- [scripts/upload.sh:1-128](file://scripts/upload.sh#L1-L128) - [scripts/upload.sh:1-128](file://scripts/upload.sh#L1-L128)
- [Dockerfile.multistage:1-26](file://Dockerfile.multistage#L1-L26) - [Dockerfile.multistage:1-26](file://Dockerfile.multistage#L1-L26)
@@ -183,6 +197,7 @@ participant RS as "cache.NewClient()"
participant MS as "search.NewClient()" participant MS as "search.NewClient()"
participant S3 as "storage.NewS3Storage()" participant S3 as "storage.NewS3Storage()"
participant RT as "router.New()" participant RT as "router.New()"
participant TASK as "task.Start()"
participant HTTP as "http.Server" participant HTTP as "http.Server"
DEPLOY->>DOCKER : 本地交叉编译 DEPLOY->>DOCKER : 本地交叉编译
DEPLOY->>DOCKER : 上传二进制文件 DEPLOY->>DOCKER : 上传二进制文件
@@ -196,6 +211,7 @@ MAIN->>RS : 初始化 Redis 客户端
MAIN->>MS : 初始化 Meilisearch 客户端 MAIN->>MS : 初始化 Meilisearch 客户端
MAIN->>S3 : 初始化 S3 存储 MAIN->>S3 : 初始化 S3 存储
MAIN->>RT : 构建路由引擎 MAIN->>RT : 构建路由引擎
MAIN->>TASK : 启动定时任务
MAIN->>HTTP : 启动 HTTP 服务器 MAIN->>HTTP : 启动 HTTP 服务器
DOCKER->>DOCKER : 健康检查 DOCKER->>DOCKER : 健康检查
OS-->>MAIN : 发送终止信号 OS-->>MAIN : 发送终止信号
@@ -203,13 +219,16 @@ MAIN->>HTTP : 优雅关闭
``` ```
**图表来源** **图表来源**
- [cmd/server/main.go:38-140](file://cmd/server/main.go#L38-L140) - [cmd/server/main.go:38-148](file://cmd/server/main.go#L38-L148)
- [internal/config/config.go:24-71](file://internal/config/config.go#L24-L71) - [internal/config/config.go:24-71](file://internal/config/config.go#L24-L71)
- [pkg/logger/logger.go:8-19](file://pkg/logger/logger.go#L8-L19) - [pkg/logger/logger.go:8-19](file://pkg/logger/logger.go#L8-L19)
- [internal/database/mysql.go:14-47](file://internal/database/mysql.go#L14-L47) - [internal/database/mysql.go:14-47](file://internal/database/mysql.go#L14-L47)
- [internal/cache/redis.go:10-17](file://internal/cache/redis.go#L10-L17) - [internal/cache/redis.go:10-17](file://internal/cache/redis.go#L10-L17)
- [internal/search/meilisearch.go:17-20](file://internal/search/meilisearch.go#L17-L20) - [internal/search/meilisearch.go:17-20](file://internal/search/meilisearch.go#L17-L20)
- [internal/router/router.go:14-41](file://internal/router/router.go#L14-L41) - [internal/router/router.go:14-41](file://internal/router/router.go#L14-L41)
- [internal/task/device_persist.go:24-35](file://internal/task/device_persist.go#L24-L35)
- [internal/task/impedance_persist.go:30-41](file://internal/task/impedance_persist.go#L30-L41)
- [internal/task/share_code_persist.go:24-34](file://internal/task/share_code_persist.go#L24-L34)
- [docker-compose.yml:22-27](file://docker-compose.yml#L22-L27) - [docker-compose.yml:22-27](file://docker-compose.yml#L22-L27)
- [scripts/deploy.sh:79-93](file://scripts/deploy.sh#L79-L93) - [scripts/deploy.sh:79-93](file://scripts/deploy.sh#L79-L93)
@@ -228,7 +247,7 @@ MAIN->>HTTP : 优雅关闭
- S3配置:S3_BUCKET、AWS_REGION、AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY - S3配置:S3_BUCKET、AWS_REGION、AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY
- 均衡器配置:EQ_API_URL、EQ_EXTERNAL_API_URL - 均衡器配置:EQ_API_URL、EQ_EXTERNAL_API_URL
- 定时任务:ENABLE_PERSIST_TASK、ENABLE_IMPEDANCE_PERSIST_TASK(默认 false - 定时任务:ENABLE_PERSIST_TASK、ENABLE_IMPEDANCE_PERSIST_TASK(默认 false
- 分享码配置:SHARE_CODE_MAX_PER_MAC(默认1)、SHARE_CODE_TTL_MIN(默认30分钟) - 分享码配置:SHARE_CODE_MAX_PER_MAC(默认1)、SHARE_CODE_TTL_MIN(默认30分钟,支持m/h/d单位
- **环境差异处理** - **环境差异处理**
- **重构后**:不再区分开发环境和生产环境的硬编码配置 - **重构后**:不再区分开发环境和生产环境的硬编码配置
@@ -263,10 +282,12 @@ MAIN->>HTTP : 优雅关闭
### 缓存与搜索 ### 缓存与搜索
- Redis:按主机:端口、密码、库号初始化客户端 - Redis:按主机:端口、密码、库号初始化客户端
- Meilisearch:按主机与 API Key 初始化索引客户端,提供模型列表检索方法 - Meilisearch:按主机与 API Key 初始化索引客户端,提供模型列表检索方法
- 分享码缓存:支持TTL配置和持久化任务
**章节来源** **章节来源**
- [internal/cache/redis.go:10-17](file://internal/cache/redis.go#L10-L17) - [internal/cache/redis.go:10-17](file://internal/cache/redis.go#L10-L17)
- [internal/search/meilisearch.go:17-46](file://internal/search/meilisearch.go#L17-L46) - [internal/search/meilisearch.go:17-46](file://internal/search/meilisearch.go#L17-L46)
- [internal/cache/share_code_cache.go:133-140](file://internal/cache/share_code_cache.go#L133-L140)
### S3存储与均衡器配置 ### S3存储与均衡器配置
- S3存储:支持AWS S3桶和区域配置,开发环境可使用模拟凭据,生产环境可使用IAM角色或环境变量 - S3存储:支持AWS S3桶和区域配置,开发环境可使用模拟凭据,生产环境可使用IAM角色或环境变量
@@ -277,12 +298,33 @@ MAIN->>HTTP : 优雅关闭
- [internal/config/equalize.go:12-32](file://internal/config/equalize.go#L12-L32) - [internal/config/equalize.go:12-32](file://internal/config/equalize.go#L12-L32)
### 定时任务与分享码配置 ### 定时任务与分享码配置
- 定时任务:支持设备和分享码的定时持久化,通过 ENABLE_PERSIST_TASK 和 ENABLE_IMPEDANCE_PERSIST_TASK 控制启用 **重大更新**:新增完整的定时任务控制系统和灵活的分享码配置。
- 分享码配置:支持最大数量限制和TTL时间配置,支持多种时间单位格式(m、h、d)
- **定时任务控制**
- ENABLE_PERSIST_TASK:控制设备和分享码的定时持久化任务
- ENABLE_IMPEDANCE_PERSIST_TASK:控制耳机阻抗数据的定时持久化任务
- 任务间隔:固定5分钟执行一次
- 任务类型:设备信息持久化、分享码日志持久化、阻抗数据持久化
- **分享码配置增强**
- SHARE_CODE_MAX_PER_MAC:每个MAC地址的最大分享码数量(默认1)
- SHARE_CODE_TTL_MIN:分享码过期时间,支持多种格式:
- 纯数字:`30`30分钟)
- 带单位:`30m`30分钟)、`24h`24小时)、`7d`7天)
- 最大值限制:365天
- **任务执行流程**
- 从Redis获取待持久化数据
- 批量写入数据库
- 成功后清理Redis中的临时数据
- 失败的数据保留等待下次重试
**章节来源** **章节来源**
- [cmd/server/main.go:86-98](file://cmd/server/main.go#L86-L98) - [cmd/server/main.go:86-106](file://cmd/server/main.go#L86-L106)
- [internal/config/share_code_ttl.go:12-59](file://internal/config/share_code_ttl.go#L12-L59) - [internal/config/share_code_ttl.go:12-59](file://internal/config/share_code_ttl.go#L12-L59)
- [internal/task/device_persist.go:24-35](file://internal/task/device_persist.go#L24-L35)
- [internal/task/impedance_persist.go:30-41](file://internal/task/impedance_persist.go#L30-L41)
- [internal/task/share_code_persist.go:24-34](file://internal/task/share_code_persist.go#L24-L34)
### 路由与中间件 ### 路由与中间件
- 路由分组:/api/v1(健康检查)、/audio(品牌、型号、设备上报、模型列表等) - 路由分组:/api/v1(健康检查)、/audio(品牌、型号、设备上报、模型列表等)
@@ -357,6 +399,7 @@ MAIN --> RC["internal/cache/redis.go"]
MAIN --> SRCH["internal/search/meilisearch.go"] MAIN --> SRCH["internal/search/meilisearch.go"]
MAIN --> S3["internal/storage/s3.go"] MAIN --> S3["internal/storage/s3.go"]
MAIN --> RT["internal/router/router.go"] MAIN --> RT["internal/router/router.go"]
MAIN --> TASK["internal/task/*"]
RT --> MW["internal/middleware/*"] RT --> MW["internal/middleware/*"]
RT --> HND["internal/handler/*"] RT --> HND["internal/handler/*"]
MAIN --> LOG["pkg/logger/logger.go"] MAIN --> LOG["pkg/logger/logger.go"]
@@ -372,6 +415,7 @@ ENV["环境变量"] --> MAIN
- [cmd/server/main.go:13-28](file://cmd/server/main.go#L13-L28) - [cmd/server/main.go:13-28](file://cmd/server/main.go#L13-L28)
- [internal/router/router.go:3-12](file://internal/router/router.go#L3-L12) - [internal/router/router.go:3-12](file://internal/router/router.go#L3-L12)
- [internal/config/s3.go:1-10](file://internal/config/s3.go#L1-L10) - [internal/config/s3.go:1-10](file://internal/config/s3.go#L1-L10)
- [internal/task/device_persist.go:14-22](file://internal/task/device_persist.go#L14-L22)
- [scripts/deploy.sh:79-93](file://scripts/deploy.sh#L79-L93) - [scripts/deploy.sh:79-93](file://scripts/deploy.sh#L79-L93)
**章节来源** **章节来源**
@@ -388,6 +432,11 @@ ENV["环境变量"] --> MAIN
- 搜索与缓存 - 搜索与缓存
- 合理设置搜索 Limit 与 AttributesToRetrieve,避免返回过多字段 - 合理设置搜索 Limit 与 AttributesToRetrieve,避免返回过多字段
- 缓存命中率优先,避免频繁访问上游服务 - 缓存命中率优先,避免频繁访问上游服务
- 分享码TTL优化:支持多种时间单位格式,提高配置灵活性
- 定时任务优化
- 批量处理:一次性处理多个记录,减少数据库交互次数
- 锁机制:防止重复处理和并发冲突
- 失败重试:未成功的数据保留在Redis中等待下次重试
- 容器化优化 - 容器化优化
- 多阶段构建减少镜像大小 - 多阶段构建减少镜像大小
- 预装时区数据避免运行时下载 - 预装时区数据避免运行时下载
@@ -399,8 +448,12 @@ ENV["环境变量"] --> MAIN
**章节来源** **章节来源**
- [internal/database/mysql.go:33-35](file://internal/database/mysql.go#L33-L35) - [internal/database/mysql.go:33-35](file://internal/database/mysql.go#L33-L35)
- [cmd/server/main.go:111-117](file://cmd/server/main.go#L111-117) - [cmd/server/main.go:111-117](file://cmd/server/main.go#L111-L117)
- [internal/middleware/logger.go:37-43](file://internal/middleware/logger.go#L37-L43) - [internal/middleware/logger.go:37-43](file://internal/middleware/logger.go#L37-L43)
- [internal/config/share_code_ttl.go:12-59](file://internal/config/share_code_ttl.go#L12-L59)
- [internal/task/device_persist.go:87-108](file://internal/task/device_persist.go#L87-L108)
- [internal/task/impedance_persist.go:87-107](file://internal/task/impedance_persist.go#L87-L107)
- [internal/task/share_code_persist.go:69-75](file://internal/task/share_code_persist.go#L69-L75)
- [Dockerfile.multistage:15-17](file://Dockerfile.multistage#L15-L17) - [Dockerfile.multistage:15-17](file://Dockerfile.multistage#L15-L17)
- [scripts/deploy.sh:96-99](file://scripts/deploy.sh#L96-L99) - [scripts/deploy.sh:96-99](file://scripts/deploy.sh#L96-L99)
@@ -417,6 +470,12 @@ ENV["环境变量"] --> MAIN
- 启动失败(S3连接) - 启动失败(S3连接)
- 现象:S3存储初始化失败 - 现象:S3存储初始化失败
- 排查:确认S3桶、区域和凭据配置;检查AWS IAM权限 - 排查:确认S3桶、区域和凭据配置;检查AWS IAM权限
- 定时任务问题
- 现象:数据未持久化到数据库
- 排查:确认 ENABLE_PERSIST_TASK 和 ENABLE_IMPEDANCE_PERSIST_TASK 设置为 true;检查Redis中的数据;查看任务日志
- 分享码配置问题
- 现象:分享码创建失败或过期时间异常
- 排查:确认 SHARE_CODE_TTL_MIN 格式正确(支持数字、m/h/d单位);检查 SHARE_CODE_MAX_PER_MAC 设置
- 容器启动失败 - 容器启动失败
- 现象:Docker容器无法启动或频繁重启 - 现象:Docker容器无法启动或频繁重启
- 排查:检查环境变量配置、健康检查端点、日志输出 - 排查:检查环境变量配置、健康检查端点、日志输出
@@ -431,14 +490,16 @@ ENV["环境变量"] --> MAIN
**章节来源** **章节来源**
- [cmd/server/main.go:57-60](file://cmd/server/main.go#L57-L60) - [cmd/server/main.go:57-60](file://cmd/server/main.go#L57-L60)
- [internal/config/database.go:57-71](file://internal/config/database.go#L57-L71) - [internal/config/database.go:57-71](file://internal/config/database.go#L57-L71)
- [internal/config/redis.go:51-56](file://internal/config/redis.go#L51-L56) - [internal/config/redis.go:51-56](file://internal/config/redis.go#L51-56)
- [internal/config/meilisearch.go:39-50](file://internal/config/meilisearch.go#L39-L50) - [internal/config/meilisearch.go:39-50](file://internal/config/meilisearch.go#L39-L50)
- [internal/middleware/logger.go:22-43](file://internal/middleware/logger.go#L22-L43) - [internal/middleware/logger.go:22-43](file://internal/middleware/logger.go#L22-L43)
- [internal/task/device_persist.go:41-49](file://internal/task/device_persist.go#L41-L49)
- [internal/task/impedance_persist.go:47-55](file://internal/task/impedance_persist.go#L47-L55)
- [scripts/deploy.sh:40-48](file://scripts/deploy.sh#L40-L48) - [scripts/deploy.sh:40-48](file://scripts/deploy.sh#L40-L48)
- [README.md:83-99](file://README.md#L83-L99) - [README.md:83-99](file://README.md#L83-L99)
## 结论 ## 结论
本项目提供了清晰的配置加载、中间件与路由结构,以及对数据库、缓存与搜索服务的标准化接入。**经过配置管理系统的重大重构,现在完全采用环境变量驱动的配置方式,移除了所有硬编码的环境特定值,实现了真正的配置外置化和环境隔离。** 配合生产/开发差异化日志与 Gin 模式,可实现稳定高效的部署与运维。新增的Docker支持和完整的部署脚本自动化功能进一步增强了部署灵活性,提供了多阶段构建、健康检查、批量部署、代码同步和CSV文件整理等完整运维能力。建议在生产环境中严格管理密钥与网络访问控制,并结合监控与日志体系完善可观测性。 本项目提供了清晰的配置加载、中间件与路由结构,以及对数据库、缓存与搜索服务的标准化接入。**经过配置管理系统的重大重构,现在完全采用环境变量驱动的配置方式,移除了所有硬编码的环境特定值,实现了真正的配置外置化和环境隔离。** 新增的定时任务控制系统和灵活的分享码配置进一步增强了系统的可配置性和运维便利性。配合生产/开发差异化日志与 Gin 模式,可实现稳定高效的部署与运维。完善的Docker支持和自动化部署脚本功能提供了多阶段构建、健康检查、批量部署、代码同步和CSV文件整理等完整运维能力。建议在生产环境中严格管理密钥与网络访问控制,并结合监控与日志体系完善可观测性。
## 附录 ## 附录
@@ -455,7 +516,7 @@ ENV["环境变量"] --> MAIN
- [README.md:75-81](file://README.md#L75-L81) - [README.md:75-81](file://README.md#L75-L81)
### 环境变量与默认值 ### 环境变量与默认值
**重大更新**:所有配置现在完全通过环境变量管理,移除了硬编码的环境特定值。 **重大更新**:所有配置现在完全通过环境变量管理,移除了硬编码的环境特定值,新增了定时任务和分享码配置
- 基础配置:APP_ENV、APP_HOST、APP_PORT、GIN_MODE - 基础配置:APP_ENV、APP_HOST、APP_PORT、GIN_MODE
- 数据库配置:DATABASE_HOST、DATABASE_PORT、DATABASE_NAME、DATABASE_USER、DATABASE_PASSWORD - 数据库配置:DATABASE_HOST、DATABASE_PORT、DATABASE_NAME、DATABASE_USER、DATABASE_PASSWORD
@@ -463,16 +524,18 @@ ENV["环境变量"] --> MAIN
- 搜索配置:MEILISEARCH_HOST、MEILISEARCH_API_KEY、MEILISEARCH_INDEX - 搜索配置:MEILISEARCH_HOST、MEILISEARCH_API_KEY、MEILISEARCH_INDEX
- S3配置:S3_BUCKET、AWS_REGION、AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY - S3配置:S3_BUCKET、AWS_REGION、AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY
- 均衡器配置:EQ_API_URL、EQ_EXTERNAL_API_URL - 均衡器配置:EQ_API_URL、EQ_EXTERNAL_API_URL
- 任务配置:ENABLE_PERSIST_TASK、ENABLE_IMPEDANCE_PERSIST_TASK - **新增任务配置**ENABLE_PERSIST_TASK、ENABLE_IMPEDANCE_PERSIST_TASK
- 分享码配置:SHARE_CODE_MAX_PER_MAC、SHARE_CODE_TTL_MIN - **新增分享码配置**SHARE_CODE_MAX_PER_MAC、SHARE_CODE_TTL_MIN(支持m/h/d单位)
**最佳实践** **最佳实践**
- 开发环境:使用 .env 文件管理本地配置 - 开发环境:使用 .env 文件管理本地配置
- 生产环境:通过容器环境变量或配置中心注入敏感配置 - 生产环境:通过容器环境变量或配置中心注入敏感配置
- 所有环境差异通过环境变量控制,避免硬编码 - 所有环境差异通过环境变量控制,避免硬编码
- 定时任务根据实际需求启用,避免不必要的资源消耗
**章节来源** **章节来源**
- [internal/config/config.go:18-95](file://internal/config/config.go#L18-L95) - [internal/config/config.go:18-95](file://internal/config/config.go#L18-L95)
- [internal/config/share_code_ttl.go:12-59](file://internal/config/share_code_ttl.go#L12-L59)
- [README.md:39-73](file://README.md#L39-L73) - [README.md:39-73](file://README.md#L39-L73)
### Docker 容器化部署 ### Docker 容器化部署
@@ -498,8 +561,8 @@ ENV["环境变量"] --> MAIN
### 监控与告警 ### 监控与告警
- 指标:QPS、P95/P99 延迟、错误率、连接池使用率、搜索延迟、容器资源使用 - 指标:QPS、P95/P99 延迟、错误率、连接池使用率、搜索延迟、容器资源使用
- 日志:请求日志、错误日志、启动/关闭事件、容器健康状态 - 日志:请求日志、错误日志、启动/关闭事件、容器健康状态、定时任务执行日志
- 告警:错误率阈值、延迟阈值、连接池耗尽、外部服务不可用、容器重启 - 告警:错误率阈值、延迟阈值、连接池耗尽、外部服务不可用、容器重启、定时任务失败
### 备份与恢复 ### 备份与恢复
- 数据库:定期逻辑备份与增量备份,验证恢复流程 - 数据库:定期逻辑备份与增量备份,验证恢复流程
File diff suppressed because one or more lines are too long
+48
View File
@@ -252,6 +252,54 @@ const docTemplate = `{
} }
} }
}, },
"/audio/getVerName": {
"get": {
"description": "根据设备型号和版本号(verCode)定位唯一 OTA 记录,返回版本名称 verName",
"produces": [
"application/json"
],
"tags": [
"OTA"
],
"summary": "查询版本名称",
"parameters": [
{
"type": "string",
"description": "设备型号",
"name": "model",
"in": "query",
"required": true
},
{
"type": "integer",
"description": "版本号 (verCode)",
"name": "version",
"in": "query",
"required": true
}
],
"responses": {
"200": {
"description": "成功返回 verName",
"schema": {
"type": "object"
}
},
"400": {
"description": "Bad Request",
"schema": {
"type": "object"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"type": "object"
}
}
}
}
},
"/audio/modelCurve": { "/audio/modelCurve": {
"get": { "get": {
"description": "返回指定机型的频响曲线数据(fr),固定使用 Harman over-ear 2018 target", "description": "返回指定机型的频响曲线数据(fr),固定使用 Harman over-ear 2018 target",
+48
View File
@@ -245,6 +245,54 @@
} }
} }
}, },
"/audio/getVerName": {
"get": {
"description": "根据设备型号和版本号(verCode)定位唯一 OTA 记录,返回版本名称 verName",
"produces": [
"application/json"
],
"tags": [
"OTA"
],
"summary": "查询版本名称",
"parameters": [
{
"type": "string",
"description": "设备型号",
"name": "model",
"in": "query",
"required": true
},
{
"type": "integer",
"description": "版本号 (verCode)",
"name": "version",
"in": "query",
"required": true
}
],
"responses": {
"200": {
"description": "成功返回 verName",
"schema": {
"type": "object"
}
},
"400": {
"description": "Bad Request",
"schema": {
"type": "object"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"type": "object"
}
}
}
}
},
"/audio/modelCurve": { "/audio/modelCurve": {
"get": { "get": {
"description": "返回指定机型的频响曲线数据(fr),固定使用 Harman over-ear 2018 target", "description": "返回指定机型的频响曲线数据(fr),固定使用 Harman over-ear 2018 target",
+32
View File
@@ -162,6 +162,38 @@ paths:
summary: 获取耳机原始频响 CSV 数据 summary: 获取耳机原始频响 CSV 数据
tags: tags:
- Curve - Curve
/audio/getVerName:
get:
description: 根据设备型号和版本号(verCode)定位唯一 OTA 记录,返回版本名称 verName
parameters:
- description: 设备型号
in: query
name: model
required: true
type: string
- description: 版本号 (verCode)
in: query
name: version
required: true
type: integer
produces:
- application/json
responses:
"200":
description: 成功返回 verName
schema:
type: object
"400":
description: Bad Request
schema:
type: object
"500":
description: Internal Server Error
schema:
type: object
summary: 查询版本名称
tags:
- OTA
/audio/modelCurve: /audio/modelCurve:
get: get:
description: 返回指定机型的频响曲线数据(fr),固定使用 Harman over-ear 2018 target description: 返回指定机型的频响曲线数据(fr),固定使用 Harman over-ear 2018 target
+45
View File
@@ -20,6 +20,51 @@ func NewOTAHandler(repo *repository.OTARepository, log *zap.Logger) *OTAHandler
return &OTAHandler{repo: repo, log: log} return &OTAHandler{repo: repo, log: log}
} }
// GetVerName 查询版本名称
//
// @Summary 查询版本名称
// @Description 根据设备型号和版本号(verCode)定位唯一 OTA 记录,返回版本名称 verName
// @Tags OTA
// @Produce json
// @Param model query string true "设备型号"
// @Param version query int true "版本号 (verCode)"
// @Success 200 {object} object "成功返回 verName"
// @Failure 400 {object} object
// @Failure 500 {object} object
// @Router /audio/getVerName [get]
func (h *OTAHandler) GetVerName(c *gin.Context) {
modelVal := strings.TrimSpace(c.Query("model"))
versionStr := strings.TrimSpace(c.Query("version"))
// 参数校验
if modelVal == "" || versionStr == "" {
response.BadRequest(c, "model和version参数不能为空")
return
}
version, err := strconv.Atoi(versionStr)
if err != nil {
response.BadRequest(c, "version参数格式错误")
return
}
ctx := c.Request.Context()
verName, found, err := h.repo.GetVerNameByVersion(ctx, modelVal, version)
if err != nil {
h.log.Error("query ota verName failed", zap.Error(err))
response.InternalError(c, "查询版本名称失败")
return
}
if !found {
response.Fail(c, http.StatusOK, 40004, "无OTA版本信息")
return
}
response.OK(c, gin.H{"verName": verName})
}
// GetOTA 获取 OTA 升级信息 // GetOTA 获取 OTA 升级信息
// //
// @Summary 获取 OTA 升级信息 // @Summary 获取 OTA 升级信息
+15
View File
@@ -131,6 +131,21 @@ func (r *OTARepository) GetLatestOTANotTarget(ctx context.Context, modelVal stri
return &o, nil return &o, nil
} }
// GetVerNameByVersion 按 model+verCode 查询版本名称
func (r *OTARepository) GetVerNameByVersion(ctx context.Context, modelVal string, version int) (string, bool, error) {
const query = `SELECT verName FROM ota WHERE model = ? AND verCode = ? LIMIT 1`
var verName string
err := r.db.QueryRowContext(ctx, query, modelVal, version).Scan(&verName)
if err == sql.ErrNoRows {
return "", false, nil
}
if err != nil {
return "", false, fmt.Errorf("query ota verName: %w", err)
}
return verName, true, nil
}
// IsInBlackList 检查 mac 是否在指定 ota_id 的黑名单中 // IsInBlackList 检查 mac 是否在指定 ota_id 的黑名单中
func (r *OTARepository) IsInBlackList(ctx context.Context, otaID int, mac string) (bool, error) { func (r *OTARepository) IsInBlackList(ctx context.Context, otaID int, mac string) (bool, error) {
const query = `SELECT COUNT(*) FROM black_list WHERE ota_id = ? AND mac = ?` const query = `SELECT COUNT(*) FROM black_list WHERE ota_id = ? AND mac = ?`
+1
View File
@@ -69,6 +69,7 @@ func New(log *zap.Logger, db *sql.DB, searchClient *search.Client, rdb *redis.Cl
audio.GET("/reportDevInfo", device.ReportDevInfo) audio.GET("/reportDevInfo", device.ReportDevInfo)
audio.GET("/reportImpedance", impedance.ReportImpedance) audio.GET("/reportImpedance", impedance.ReportImpedance)
audio.GET("/ota", ota.GetOTA) audio.GET("/ota", ota.GetOTA)
audio.GET("/getVerName", ota.GetVerName)
audio.GET("/getCurve", middleware.CacheControl(middleware.CacheControlCurve), curve.GetCurve) audio.GET("/getCurve", middleware.CacheControl(middleware.CacheControlCurve), curve.GetCurve)
audio.GET("/modelCurve", middleware.CacheControl(middleware.CacheControlCurve), curve.ModelCurve) audio.GET("/modelCurve", middleware.CacheControl(middleware.CacheControlCurve), curve.ModelCurve)
audio.GET("/getModelCSV", modelCSV.GetModelCSV) audio.GET("/getModelCSV", modelCSV.GetModelCSV)