feat: 添加数据库集成、定时任务调度器和事件Hook体系

- 新增数据库配置项(DB_TYPE, DB_HOST, DB_PORT等),支持MySQL和PostgreSQL
- 集成GORM实现数据库连接和自动迁移功能
- 添加定时任务调度器(cmd/scheduler),基于robfig/cron实现秒级调度
- 实现事件Hook体系,支持同步/异步处理和优先级排序
- 更新构建脚本,编译server、cli、scheduler三个二进制文件
- 配置systemd服务管理定时任务调度器
- 重构项目结构,新增crontab和hooks目录模块
- 更新README文档,完善各组件使用说明和部署配置
This commit is contained in:
shiran
2026-04-15 12:39:59 +08:00
parent 6050d11f27
commit aa9f892a32
22 changed files with 753 additions and 141 deletions
+162 -118
View File
@@ -1,6 +1,6 @@
# apiServer 微服务模板
基于 [CloudWego Hertz](https://github.com/cloudwego/hertz) 的 Go 微服务脚手架,集成 Nacos 服务注册/发现 + gRPC 客户端 + 访问日志上报(Redis → ES)。
基于 [CloudWego Hertz](https://github.com/cloudwego/hertz) 的 Go 微服务脚手架,集成 Nacos 服务注册/发现 + gRPC 客户端 + 访问日志上报(Redis → ES)+ 定时任务 + 事件 Hook 体系
## 项目结构
@@ -8,19 +8,27 @@
├── apps/ # 业务处理层 (Handler)
├── cmd/
│ ├── main_program/ # 主程序入口 (HTTP 服务)
── cli_control/ # CLI 工具入口 (httplog 上报)
── cli_control/ # CLI 工具入口 (httplog 上报)
│ └── scheduler/ # 定时任务调度器 (独立进程)
├── crontab/ # 定时任务框架
│ └── tasks/ # 具体任务实现
├── hooks/ # 事件 Hook 体系
│ └── registers/ # Hook 注册入口
├── middleware/ # HTTP 中间件 (Recovery, AccessLog, CORS)
├── models/request_models/ # 请求参数模型
├── models/
│ ├── database/ # 数据库连接 & ORM 模型 (GORM)
│ └── request_models/ # 请求参数模型
├── proto/ # Protobuf 生成代码
├── routes/ # 路由定义
├── utils/
│ ├── httplog/ # HTTP 访问日志采集 & ES 上报
│ ├── logger/ # 日志工具 (logrus)
│ ├── logger/ # 日志工具 (logrus,主服务/定时任务分离)
│ ├── nacos/ # Nacos 服务注册/发现/配置
│ ├── redis_tools/ # Redis 连接 & 通用操作
│ ├── request/ # 请求绑定 & 统一响应
│ └── server_cli/ # gRPC 客户端
├── start.sh / stop.sh / restart.sh
├── deploy/ # systemd 服务单元
├── start.sh / stop.sh / restart.sh / install.sh
├── .env.example # 环境变量示例
└── go.mod
```
@@ -38,10 +46,12 @@ go mod tidy
# 3. 开发运行
go run ./cmd/main_program # HTTP 服务
go run ./cmd/cli_control # httplog 上报
go run ./cmd/scheduler # 定时任务调度器
# 4. 构建
go build -ldflags="-s -w" -o server ./cmd/main_program
go build -ldflags="-s -w" -o cli ./cmd/cli_control
go build -ldflags="-s -w" -o scheduler ./cmd/scheduler
```
## 模板使用步骤
@@ -58,111 +68,164 @@ go build -ldflags="-s -w" -o cli ./cmd/cli_control
### cmd/main_program — HTTP 主服务
启动 Hertz HTTP 服务,绑定路由和中间件,可选注册到 Nacos。
启动 Hertz HTTP 服务,绑定路由和中间件,可选连接数据库、注册到 Nacos。
```bash
go run ./cmd/main_program
```
启动流程:加载 `.env` → 校验 `HOST`/`PORT`注册中间件(Recovery、AccessLog、CORS→ 绑定路由 → Nacos 注册(可选)→ 启动 HTTP 监听 → 等待信号优雅关闭。
启动流程:加载 `.env` → 校验 `HOST`/`PORT`连接数据库(可选)→ 注册中间件 → 绑定路由 → Nacos 注册(可选)→ HTTP 监听 → 等待信号优雅关闭。
### cmd/cli_control — httplog 日志上报
独立后台进程,从 Redis 队列消费访问日志,批量写入 Elasticsearch。
独立后台进程,从 Redis 队列消费访问日志,批量写入 Elasticsearch。
```bash
go run ./cmd/cli_control
```
启动后会以轮询方式从 `ES_REDIS_KEY` 队列中批量 pop 日志条目,组装 ES `_bulk` 请求写入 `ES_INDEX_PREFIX-YYYY.MM.DD` 索引。
### cmd/scheduler — 定时任务调度器
独立进程运行定时任务,使用专用日志文件 `logs/cron_*.log`
```bash
go run ./cmd/scheduler # 常驻模式
go run ./cmd/scheduler list # 列出已注册任务
go run ./cmd/scheduler run-once # 立即执行所有任务一次
go run ./cmd/scheduler run 健康检查 # 立即执行指定任务
```
### crontab — 定时任务框架
基于 `robfig/cron` 的调度器,支持秒级 cron 表达式,内置 panic 恢复。
**新增任务三步走:**
```go
// 1. 在 crontab/tasks/ 下新建文件,实现 Task 接口
type MyTask struct{}
func (t *MyTask) Name() string { return "我的任务" }
func (t *MyTask) Spec() string { return "0 */10 * * * *" } // 每10分钟
func (t *MyTask) Run() {
logger.CronInfo("MyTask", "执行中...")
}
// 2. 在 crontab/tasks/register.go 注册
func RegisterTasks(scheduler *crontab.Scheduler) {
scheduler.Register(&HealthCheckTask{})
scheduler.Register(&MyTask{}) // 新增
}
// 3. 完成,scheduler 进程会自动调度
```
定时任务日志独立写入 `logs/cron_YYYYMMDD.log`,不与主服务日志混合。
### hooks — 事件 Hook 体系
发布-订阅模式的业务事件系统,支持同步/异步处理和优先级排序。
**触发事件:**
```go
import "apiServer_service/hooks"
hooks.DefaultManager().Trigger(ctx, hooks.EventType("order_paid"), &hooks.EventPayload{
UserID: 123,
Extra: map[string]any{"order_id": 456, "amount": 99.9},
})
```
**注册 Handler**
```go
// hooks/registers/register.go
func RegisterHooks(m *hooks.Manager) {
// 同步处理(按优先级顺序执行,阻塞直到完成)
m.Register(hooks.EventType("order_paid"), hooks.HandlerFunc(OnOrderPaid))
// 异步处理(不阻塞主流程)
m.RegisterAsync(hooks.EventType("order_paid"), hooks.HandlerFunc(SendNotification))
// 指定优先级(数值越大越先执行)
m.RegisterWithPriority(hooks.EventType("order_paid"), 10, hooks.HandlerFunc(DeductInventory))
}
func OnOrderPaid(ctx context.Context, event hooks.EventType, payload *hooks.EventPayload) error {
// 业务逻辑
return nil
}
```
**特性:**
| 能力 | 说明 |
|------|------|
| 同步执行 | `Register` — 按优先级顺序执行,阻塞调用方 |
| 异步执行 | `RegisterAsync` — goroutine 执行,不阻塞 |
| 优先级 | `RegisterWithPriority` — 数值越大越先执行 |
| panic 安全 | 异步 handler panic 不影响主流程 |
| 函数适配 | `HandlerFunc` 可直接用匿名函数注册 |
### middleware — HTTP 中间件
`cmd/main_program/routs.go` 中统一注册:
```go
r.Use(middleware.Recovery()) // panic 恢复,防止单个请求崩溃整个服务
r.Use(middleware.AccessLog()) // 请求日志(方法、路径、状态码、耗时)
r.Use(middleware.Recovery()) // panic 恢复
r.Use(middleware.AccessLog()) // 请求日志
r.Use(middleware.CORS()) // 跨域支持
```
### utils/httplog — 访问日志采集
### models/database — 数据库 (GORM)
Hertz Tracer 实现,在请求完成后采集完整的访问事件(方法、路径、状态码、耗时、请求体、响应体等),通过 Redis List 异步缓冲
**在主服务中接入:**
支持 MySQL 和 PostgreSQL`DB_TYPE` 为空时跳过连接
```go
import (
"apiServer_service/utils/httplog"
"apiServer_service/utils/redis_tools"
"github.com/cloudwego/hertz/pkg/app/server"
)
import db "apiServer_service/models/database"
db.GetDB().Where("parent_id = ?", 0).Find(&groups)
db.GetDB().Create(&db.HostGroup{Name: "生产环境"})
```
新增模型在 `models/database/` 下定义结构体,在 `init.go``Migrate()` 中注册。
### utils/httplog — 访问日志采集
Hertz Tracer 实现,采集访问事件通过 Redis List 异步缓冲,由 `cli` 进程批量写入 ES。
```go
rdb := redis_tools.ConnectRedis()
tracer := httplog.NewRedisAccessLogTracer(rdb, "access_log", "my-service",
httplog.WithSkipPrefix("/health"), // 跳过健康检查路径
httplog.WithMaxResponseBody(4096), // 响应体最大采集 4KB
httplog.WithUserIDExtractor(func(c *app.RequestContext) uint {
// 根据你的认证方式提取 user_id
return 0
}),
httplog.WithSkipPrefix("/health"),
httplog.WithMaxResponseBody(4096),
httplog.WithUserIDExtractor(func(c *app.RequestContext) uint { return 0 }),
)
h := server.Default(server.WithTracer(tracer))
```
**特性:**
- 敏感字段自动脱敏(password, token, secret 等)
- multipart 文件字段替换为 `[file]` 占位符
- 非文本响应自动跳过(图片、zip 等)
- 异步写入 Redis,队列满时丢弃(不阻塞业务)
### utils/redis_tools — Redis 工具
单例连接,提供通用 KV 和 List 操作:
```go
import "apiServer_service/utils/redis_tools"
// 连接(全局只初始化一次)
rdb := redis_tools.ConnectRedis()
// KV 操作
redis_tools.SetCache("key", "value", 10*time.Minute)
val, err := redis_tools.GetCache("key")
val, _ := redis_tools.GetCache("key")
redis_tools.Del("key1", "key2")
redis_tools.Exists("key")
// List 操作
redis_tools.AddToList("queue", "item")
items, _ := redis_tools.GetAllFromList("queue")
redis_tools.RemoveFromList("queue", "item")
```
### utils/nacos — Nacos 服务注册/发现/配置
```go
import "apiServer_service/utils/nacos"
// 注册当前服务(读取 NACOS_SERVICE_* 环境变量)
nacos.RegisterService()
// 发现服务(带内存缓存)
instance, err := nacos.DiscoverService("user-service")
addr := instance.Ip + ":" + strconv.Itoa(int(instance.Port))
// 配置管理
instance, _ := nacos.DiscoverService("user-service")
content := nacos.GetConfig("app.yaml", "DEFAULT_GROUP")
nacos.AddConfig("app.yaml", "DEFAULT_GROUP", "key: value")
```
### utils/server_cli — gRPC 客户端
通过 Nacos 服务发现获取 gRPC 地址,连接复用:
```go
import "apiServer_service/utils/server_cli"
err := server_cli.ReportVisit(token, note, ip, os, point, userId)
defer server_cli.CloseGrpcConn()
```
@@ -170,37 +233,24 @@ defer server_cli.CloseGrpcConn()
### utils/request — 请求绑定 & 统一响应
```go
import "apiServer_service/utils/request"
// 参数绑定(失败自动返回 400
var req MyRequest
if err := request.BindRequestStruct(c, &req); err != nil {
return
}
// 统一响应
request.Success(c, data) // 200 {"code":200,"message":"Success","data":...}
request.BadRequest(c, "参数错误") // 400
request.Unauthorized(c, "未登录") // 401
request.NotFound(c, "资源不存在") // 404
request.Error(c, 500, "服务器内部错误") // 自定义状态码
request.FileResponse(c, "/path/to/file", "download.zip")
request.BindRequestStruct(c, &req) // 失败自动 400
request.Success(c, data) // 200
request.BadRequest(c, "参数错误") // 400
request.Unauthorized(c, "未登录") // 401
request.NotFound(c, "不存在") // 404
request.Error(c, 500, "错误") // 自定义
request.FileResponse(c, path, name) // 文件下载
```
### routes — 路由定义
`routes/` 下按模块拆分路由文件,在 `cmd/main_program/routs.go` 中注册:
```go
func SetupRoutes(r *server.Hertz) {
r.Use(middleware.Recovery())
r.Use(middleware.AccessLog())
r.Use(middleware.CORS())
r.Use(middleware.Recovery(), middleware.AccessLog(), middleware.CORS())
api := r.Group("/api")
{
routes.RegisterIndexRoutes(api)
// routes.RegisterUserRoutes(api) // 新增模块在此注册
// routes.RegisterUserRoutes(api) // 新增模块在此注册
}
}
```
@@ -214,40 +264,32 @@ func SetupRoutes(r *server.Hertz) {
```bash
go build -ldflags="-s -w" -o server ./cmd/main_program
go build -ldflags="-s -w" -o cli ./cmd/cli_control
go build -ldflags="-s -w" -o scheduler ./cmd/scheduler
```
### 首次安装(systemd 服务注册)
将二进制、`.env`、脚本和 `deploy/` 目录上传到服务器后执行:
```bash
chmod +x install.sh start.sh stop.sh restart.sh server cli
# 安装 systemd 服务 + 设置开机自启
chmod +x install.sh start.sh stop.sh restart.sh server cli scheduler
sudo bash install.sh
```
`install.sh` 会自动:
1.`deploy/*.service` 适配当前路径后复制到 `/etc/systemd/system/`
2. 执行 `systemctl daemon-reload`
3. 执行 `systemctl enable server cli` 开机自启
### 日常运维
```bash
bash start.sh # 启动全部服务
bash stop.sh # 停止全部服务
bash restart.sh # 重启全部服务
bash start.sh # 启动全部 (server + cli + scheduler)
bash stop.sh # 停止全部
bash restart.sh # 重启全部
```
也可以直接使用 `systemctl` 管理单个服务
单独管理
```bash
systemctl status server # 查看主服务状态
systemctl status cli # 查看 CLI 状态
systemctl restart server # 只重启主服务
journalctl -u server -f # 查看主服务实时日志
journalctl -u cli -f --since today # 查看 CLI 今日日志
systemctl status server # 主服务状态
systemctl status scheduler # 调度器状态
systemctl restart scheduler # 只重启调度器
journalctl -u server -f # 主服务实时日志
journalctl -u scheduler -f # 调度器实时日志
```
### systemd 服务特性
@@ -255,41 +297,43 @@ journalctl -u cli -f --since today # 查看 CLI 今日日志
| 特性 | 说明 |
|------|------|
| 开机自启 | `install.sh` 执行后自动启用 |
| 崩溃自动重启 | `Restart=always`server 间隔 3scli 间隔 5s |
| 优雅关闭 | `KillSignal=SIGTERM`,等待 10s 超时后 SIGKILL |
| 环境变量 | 通过 `EnvironmentFile` 加载 `.env` |
| 崩溃自动重启 | `Restart=always`server 3s / cli 5s / scheduler 5s |
| 优雅关闭 | `SIGTERM`server 10s / scheduler 15s 超时 |
| 环境变量 | `EnvironmentFile` 加载 `.env` |
| 文件描述符 | `LimitNOFILE=65536` |
| 日志 | 同时写入 `logs/*.out``journalctl` |
### 部署目录结构
```
/root/
├── server # HTTP 主服务二进制
├── cli # httplog 上报二进制
├── server # HTTP 主服务
├── cli # httplog 上报
├── scheduler # 定时任务调度器
├── .env # 环境配置
├── deploy/
│ ├── server.service # systemd 服务单元(模板)
── cli.service
├── install.sh # 首次安装脚本
├── start.sh # 启动
├── stop.sh # 停止
├── restart.sh # 重启
│ ├── server.service
── cli.service
│ └── scheduler.service
├── install.sh / start.sh / stop.sh / restart.sh
└── logs/
├── server.out
── cli.out
├── server.out # 主服务输出
── cli.out # httplog 输出
├── scheduler.out # 调度器输出
└── cron_*.log # 定时任务专用日志
```
## 内置功能清单
- Hertz HTTP 框架 + 路由分组
- Recovery / AccessLog / CORS 中间件
- 统一 JSON 响应格式
- 参数绑定与校验
- 统一 JSON 响应格式 + 参数绑定校验
- GORM 数据库(MySQL / PostgreSQL,自动迁移)
- 事件 Hook 体系(同步/异步、优先级、发布-订阅)
- 定时任务调度器(秒级 cron、独立进程、专用日志)
- HTTP 访问日志采集 → Redis 缓冲 → ES 批量上报
- Redis 工具(单例连接池)
- Nacos 服务注册、发现、配置管理
- gRPC 客户端(连接复用)
- 彩色日志输出 + 文件日志
- gRPC 客户端(连接复用)
- 彩色日志 + 文件日志(主服务/定时任务分离)
- 优雅关闭 (Graceful Shutdown)
- systemd 服务管理(开机自启 + 崩溃自动重启)