# GoOmni GoOmni 是一套面向业务复用的 Go 后端基础框架。当前默认使用只依赖标准库的网络适配器,业务代码只依赖 GoOmni 的 transport-neutral API,后续可以替换为自研网络层。 远程 module 地址是 `git.yuntuo.hk/k2safe/go-omni`。业务项目可以直接引用指定版本: ```sh go get git.yuntuo.hk/k2safe/go-omni@v0.7.0-preview ``` `v0.4.0` 移除了 Gin 和 Gin 专属的 `WithMode` 配置;`omni.New()` 直接使用标准库路由,已有业务 Handler / Service 无需修改。 创建新业务项目: ```sh go install git.yuntuo.hk/k2safe/go-omni/cmd/go-omni@v0.7.0-preview go-omni new --module example.com/billing ./billing cd billing go mod tidy go run ./cmd/server ``` 远程安装的 CLI 默认引用自身版本,生成的项目不需要本地 `replace`。 具体版本和本地开发选项见 [CLI 文档](cmd/go-omni/README.md)。 需要数据库持久化时,使用 `go-omni new --database mysql --module example.com/billing ./billing`。 生成项目包含完整用户 CRUD、数据库 Repository、ServiceContext、建表脚本和就绪探针。 先应用生成的 `schema.sql`,再配置 `GO_OMNI_DB_DSN`;启动时会检查连接与表结构,退出时释放连接池。 ## API 定义与项目生成 当前源码新增 **API 定义驱动项目生成**:写 `.api` 定义请求、响应和路由,自动生成项目目录、DTO、Handler、Service 骨架及 OpenAPI。重复生成保留业务代码,支持只读 CI 检查,完整语法和示例见 [API 开发指南](API.md)。 ```sh go run ./cmd/go-omni api new --framework-dir . \ --module example.com/omniDemo ../omniDemo ``` API 生成支持 `--database mysql --storage local --log-output file` 组合初始化。上面的命令使用本地源码;远程安装见 [发布说明](RELEASE.md),完整业务案例见 [userService](examples/userService/README.md)。 ## 目录结构 ```text go-omni/ ├── app/ # 应用启动和生命周期 ├── httpx/ # 与网络框架无关的 HTTP 抽象 ├── response/ # 统一响应 ├── errors/ # 统一错误 ├── health/ # 存活和就绪检查 ├── middleware/ # 请求 ID 等基础中间件 ├── logx/ # 业务层结构化日志 ├── metrics/ # 请求指标与状态统计 ├── config/ # 配置管理 ├── validate/ # 参数校验 ├── contract/ # API 字段契约、严格多源绑定与文档约束 ├── auth/ # 认证和权限接口 ├── database/ # database/sql 生命周期和事务 ├── cache/ # 有界内存缓存、Redis 适配与合并回源 ├── httpc/ # 出站 HTTP 连接池、超时和重试 ├── task/ # 有界后台任务与间隔调度 ├── queue/ # 持久队列接口与 Redis Streams 适配 ├── storage/ # Local、S3/R2、OSS 与临时下载链接 ├── openapi/ # 路由和 OpenAPI 3.0.3 契约 ├── telemetry/ # 可注入 OpenTelemetry 观测 ├── resilience/ # 熔断与上游并发隔离 ├── audit/ # 显式业务审计与可注入 Sink ├── pagination/ # 有界分页和统一结果 ├── transport/nethttp/ # 标准库网络适配器 ├── transport/native/ # 自研 HTTP/1.1 服务端预览 ├── transport/http2/ # opt-in HTTP/2 实验适配器 ├── examples/ # 示例项目 └── cmd/ # go-omni 项目脚手架 ``` main 分支新增缓存、出站 HTTP、限流/幂等/超时中间件、后台任务和 `go-omni add` 模块脚手架。 使用方式、默认容量和进程内能力的适用范围见 [业务基础模块](MODULES.md), 可以直接运行 [组合示例](examples/modules/README.md)。这些能力从 `v0.7.0-preview` 提供。 扩展模块还包括 JWT/Session、Policy、文件配置及安全热更新、Redis 共享中间件、持久队列、多平台对象存储、OpenAPI、OpenTelemetry、熔断、迁移、审计和分页。 使用与边界见 [扩展模块](ADVANCED.md),可运行 [文件服务组合示例](examples/platform/README.md)。go-omni 不集成 Orbit;需要流程编排的业务项目独立接入。 ## 快速开始 ```go package main import omni "git.yuntuo.hk/k2safe/go-omni" func main() { app := omni.New() app.GET("/health", func(ctx *omni.Context) error { return ctx.OK(map[string]string{"status": "ok"}) }) app.Run(":8080") } ``` 成功响应默认使用统一结构: ```json { "code": "OK", "message": "success", "data": {"status": "ok"}, "requestId": "..." } ``` 业务错误可以直接返回: ```go return omni.NotFound("USER_NOT_FOUND", "user was not found") ``` 默认网络适配器位于 `transport/nethttp`。业务层不需要导入具体网络库;如果后续实现自己的网络层,只需要实现 `httpx.Router` / `httpx.RouterGroup`,然后通过 `omni.NewWithRouter` 启动应用: ```go application := omni.NewWithRouter(myRouter) ``` 仓库还提供了使用标准库路由的 `transport/nethttp` 参考实现。两种适配器已通过同一套路由、业务处理链和取消传播测试,完整用户 CRUD 复用同一份 Handler / Service。 自研适配器可以直接运行 `transport/transporttest.Run` 验收。具体规则、v0.4.0 的斜杠 / Any / 405 行为调整,以及自研网络内核与当前 HTTP 接口的边界,见 [适配层契约](transport/README.md)。 `app.Engine()` 返回标准 `http.Handler`,`ctx.Raw()` 返回适配器提供的 `http.ResponseWriter`,业务 API 不锁定具体网络实现。 需要试用第一版自研网络层时,业务注册代码无需改变,只替换启动器: ```go import ( "context" "log" "os" "os/signal" "syscall" omni "git.yuntuo.hk/k2safe/go-omni" "git.yuntuo.hk/k2safe/go-omni/transport/native" ) ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) defer cancel() app := omni.New() app.GET("/health", func(ctx *omni.Context) error { return ctx.OK(map[string]string{"status": "ok"}) }) if err := app.RunWith(ctx, native.New(nil), ":8080"); err != nil { log.Fatal(err) } ``` `transport/native` 当前支持 HTTP/1.1、Keep-Alive、`Content-Length` 和 chunked 请求体、`http.Flusher` 流式响应、可选 TLS、读写超时和优雅关闭;不支持的传输编码会被拒绝。它会复用连接状态和响应对象,并可通过 `MaxConnections`、`MaxConcurrentRequests` 限制内存峰值。它仍通过标准 HTTP 请求/响应接口连接业务层,适合在现有 Handler / Service 上做网络层验证。 native TLS 当前只支持并宣告 ALPN `http/1.1`;配置 `h2` 会在启动时快速失败。需要 HTTP/2 时,可由 Nginx/Cloudflare 终止后回源 HTTP/1.1,或使用默认的 `transport/nethttp` 适配器。 `transport/http2` 是独立的 opt-in 实验适配器,使用 `x/net/http2` 处理帧和流控,同时保留 GoOmni 的连接上限、全局请求并发闸门和生命周期边界。它不会改变 native 默认路径;实验入口、限制和验收结果见 [HTTP/2 进入条件](transport/native/HTTP2.md)。 自研网络层还提供 `server.Stats()`,可读取 accepted、rejected、active connections 和 active requests,与上面的业务请求 metrics 组合后能区分连接堆积、过载拒绝和 Handler 慢请求。`rejectedConnections` 表示连接闸门拒绝数,`rejectedRequests` 表示并发请求闸门返回 503 的次数。 业务代码可以直接使用 `git.yuntuo.hk/k2safe/go-omni/logx` 打结构化日志,不需要依赖具体网络库: ```go func (s *UserService) Create(ctx *httpx.Context) error { logx.InfoContext(ctx.Context(), "user.create", "email", input.Email) return nil } ``` 需要基础运行指标时,可以注册 transport-neutral metrics middleware 和接口: ```go requestMetrics := omni.NewMetrics() app.Use(requestMetrics.Middleware()) app.GET("/metrics", requestMetrics.Handler()) ``` 接口返回请求总数、错误数、当前处理中请求、累计耗时和 HTTP 状态分布。它是进程内快照,生产环境可由业务侧定时采集到监控系统。 `WithLogger(true)` 会启用 GoOmni 的统一 HTTP 访问日志;日志内容和业务日志共用 `requestId`。应用启动时可以调用 `logx.Setup` 配置 JSON/文本格式、级别、服务名和输出文件。文件轮转、敏感字段脱敏、异常堆栈与慢请求配置见 [logx 文档](logx/README.md);文件直传与云端分片上传见 [storage 文档](storage/README.md)。 创建新业务项目时可通过 `go-omni new --log-output file --storage local` 按需生成配置、装配代码与可运行示例,当前源码使用方式见 [CLI 文档](cmd/go-omni/README.md)。 应用配置可以统一从 `GO_OMNI_*` 环境变量加载,再交给 `omni.New`: ```go settings, err := omni.LoadConfig("") if err != nil { log.Fatal(err) } logger, err := logx.New(settings.Log) if err != nil { log.Fatal(err) } application := omni.New(omni.WithConfig(settings)) application.OnShutdown(logger.Close) ``` 常用变量包括 `GO_OMNI_ENABLE_LOGGER`、`GO_OMNI_LOG_LEVEL`、 `GO_OMNI_LOG_FORMAT`、`GO_OMNI_LOG_OUTPUT`、`GO_OMNI_SERVICE`、 `GO_OMNI_ENVIRONMENT`、`GO_OMNI_HTTP_ADDR`、`GO_OMNI_SHUTDOWN_TIMEOUT` 和 `GO_OMNI_TRUSTED_PROXIES`。可信代理变量使用逗号分隔的 IP/CIDR,例如 `GO_OMNI_TRUSTED_PROXIES=127.0.0.1,10.0.0.0/8`;只有来自这些地址的连接才会解析 `X-Forwarded-For`,默认只记录 socket 对端地址。数据库连接仍由 `database.ConfigFromEnv` 从 `GO_OMNI_DB_*` 加载。 网络层也由同一份配置选择,Handler / Service / Repository 不需要导入具体适配器: | 配置 | 默认值 / 用途 | | --- | --- | | `GO_OMNI_TRANSPORT` | `nethttp`;可选 `native`、`http2` | | `GO_OMNI_TLS_CERT_FILE` | TLS 证书 PEM 文件路径 | | `GO_OMNI_TLS_KEY_FILE` | TLS 私钥 PEM 文件路径,必须与证书一起配置 | | `GO_OMNI_SHUTDOWN_TIMEOUT` | `10s`,三种适配器共用的请求排空时间 | 例如运行自研 HTTP/1.1,或显式试用独立 HTTP/2 适配器: ```sh GO_OMNI_TRANSPORT=native go run ./examples/reference GO_OMNI_TRANSPORT=http2 GO_OMNI_HTTP_ADDR=127.0.0.1:8443 \ GO_OMNI_TLS_CERT_FILE=./server.crt GO_OMNI_TLS_KEY_FILE=./server.key \ go run ./examples/reference ``` `http2` 必须配置 TLS;native TLS 只协商 `http/1.1`,nethttp TLS 支持标准库的 HTTP/1.1 和 HTTP/2。 未知适配器、缺少配对证书、无法加载证书时,`Run` / `RunContext` 在监听前返回错误并执行资源清理,不会退回其他协议。 HTTP/2 仍为实验适配器,尚未合并到 native 多协议监听器。 代码配置可写成 `omni.New(omni.WithTransport(omni.TransportNative), omni.WithTLS(certFile, keyFile))`。 `ServeContext(ctx, listener)` 使用相同配置并接管已有 listener;失败或退出时也会关闭它。 `RunWith(ctx, runner)` 保留自定义网络层入口,由 runner 自己管理 TLS、超时和网络参数;连接/请求上限等适配器专属选项仍通过这个入口设置。 `NewServer` 仅创建标准库明文服务器,配置选择应用于 `Run`、`RunContext` 和 `ServeContext`。 三种适配器的配置、真实 TLS 业务和关闭行为已通过 Linux 全量 race 及 10 次重复回归,见 [统一启动验收](performance/transportStartup.md)。 `App` 同时实现标准 `http.Handler`。`Run` 监听 `SIGINT` / `SIGTERM`;`RunContext` 则由调用方的 context 控制退出,生成项目已使用 `signal.NotifyContext` 接好信号。 退出时先停止接收新请求,等待活跃请求完成,再执行资源清理。超过 `ShutdownTimeout` 时强制关闭连接、取消请求 context,并返回超时错误。业务代码应响应 context 取消;框架无法强制结束忽略取消的业务 goroutine。数据库连接池由 `database.Open` 创建,在服务退出时调用 `Close`。 应用资源可以直接挂到 `omni.New` 返回的生命周期上: ```go application := omni.New() application.OnShutdown(db.Close) ``` 清理函数会按注册顺序的逆序执行,`application.Close()` 和 `RunContext` 都会触发,且重复调用安全。 服务可以把数据库、缓存等依赖注册为就绪探针: ```go checker, err := health.New(health.Probe{ Name: "database", Check: db.PingContext, }) if err != nil { log.Fatal(err) } application.GET("/health/live", checker.LivenessHandler()) application.GET("/health/ready", checker.ReadinessHandler()) ``` 存活检查只确认进程在线;就绪检查会执行全部探针,任意依赖失败时返回 HTTP 503。 新项目脚手架会生成项目自己的 `internal/servicecontext`。它集中保存 Logger、数据库、缓存和外部客户端,Service 只依赖这个项目上下文,不把基础设施初始化散落到各个 Handler: ```go services, err := servicecontext.New(ctx, logger) if err != nil { return err } defer services.Close() userService := service.NewUsers(services) ``` ## 完整业务参考项目 [`examples/reference`](examples/reference/README.md) 提供按 Handler / Service / Repository / Model 分层的用户 CRUD 示例。默认使用并发安全的内存存储,支持分页、邮箱唯一校验、结构化请求日志和统一错误,无需配置数据库。 从远程版本生成并升级一个独立业务模块,可运行: ```sh python3 scripts/verifyBusiness.py --version v0.6.0-preview ``` 该验收会在临时目录中先固定 `v0.2.0`,再升级到 `v0.6.0-preview`,检查无本地 replace、配置加载、结构化日志、requestId、CRUD、校验错误、业务错误和优雅退出。 标准库与 native 的并发、延迟和长连接内存对照见 [PERFORMANCE.md](PERFORMANCE.md)。`python3 scripts/verifyPerformance.py` 运行检查与 benchmark;增加 `--load --output /tmp/goOmniPerf.json` 可测量独立服务进程并保存报告。 HTTP/2 仍是显式 opt-in 实验适配器,不会改变 native 的 HTTP/1.1 默认路径。Linux TLS 长测使用 `python3 scripts/verifyHTTP2.py --duration 30m`,默认使用普通 Go 运行模式;`--race` 默认改为 60 秒,用于并发检查,其额外内存开销不能当成生产运行基线。 多连接混合场景使用 `python3 scripts/verifyHTTP2.py --scenario mixed --duration 30m`:8 条独立 TLS 连接,每条连接 14 个普通请求 worker、1 个慢上传 worker、1 个慢下载 worker,共 128 个 worker。上传为 256 KiB、每 4 KiB 等待 2 ms;下载为 8 MiB、每次最多读取 64 KiB 后等待 20 ms。日志分别记录三类成功数、传输字节数、每条连接的覆盖情况,以及停止并释放测试数据后两次 GC 的采样。 该脚本默认把测试容器限制为 2 核、2 GiB 内存(禁用 swap)、256 个进程/线程,整个命令最多运行 40 分钟,中断和超时会清理本次容器。这些限制可用 `--cpus`、`--memory-mb`、`--pids-limit`、`--wall-timeout` 调整;共享服务器应先用 `--duration 60s` 短测,再逐步延长。每 15 秒输出的堆、RSS 和 FD 统计包含同一进程内的客户端与服务端。 Linux amd64 已完成 30 分钟、单 TLS 连接、128 个 worker 的普通模式长测:58,102,476 次请求,0 失败、0 协议错误,采样 RSS 峰值约 22.6 MiB,连接/活动请求归零且 FD 回到基线。完整采样和原始日志见 [HTTP/2 长测报告](performance/http2SoakLinux.json) 与 [原始日志](performance/http2SoakLinux.txt),此前的 race 对照见 [短测记录](performance/http2SmokeLinux.json)。这项结果覆盖单连接复用。 多连接慢客户端场景也已完成 Linux amd64 的 30 分钟长测:8 条 TLS 连接、128 个 worker,53,079,128 次普通请求、106,971 次慢上传、5,588 次慢下载,共 53,191,687 次,0 失败与协议错误。采样 RSS 峰值约 116.6 MiB(包含客户端、服务端和下载缓冲);退出后连接/请求归零,goroutine 回到 2、FD 回到 6;释放测试数据并两次 GC 后存活堆约 450 KiB,RSS 不要求立即归还操作系统。完整 120 份采样见 [混合长测报告](performance/http2MixedSoakLinux.json) 和 [原始日志](performance/http2MixedSoakLinux.txt)。连接级窗口耗尽、WINDOW_UPDATE 恢复及零窗口写阻塞的关闭回收也已有独立测试;Nginx 的 HTTP/2 回源验收结果见下方,适配器保持实验状态。 `python3 scripts/verifyHTTP2Proxy.py --count 3` 验证真实 Nginx 双段 TLS/h2、回源连接复用、证书拒绝、超时/取消恢复与新旧实例的 GOAWAY 排空;增加 `--race` 可运行并发检查。Linux amd64、Nginx 1.30.5 的普通与 race 模式各 3 轮均已通过。编译和测试容器顺序运行,均限制为 2 核、2 GiB;测试容器禁用外部网络,全部请求在容器内完成。使用方法、报告及当前边界见 [HTTP/2 代理回源验收](transport/http2/PROXY.md)。 在框架根目录运行: ```sh go run ./examples/reference ``` 默认地址为 `http://127.0.0.1:8080`。示例文档提供完整的 curl 操作流程。数据只保存在内存中,重启后清空。 框架的 `App` 也实现了标准 `http.Handler`,可以直接用于 `http.Server` 和 `httptest.NewServer`;业务路由可通过 `*omni.RouterGroup` 注册,无需导入网络库。 ## 当前边界 缓存、消息队列和定时任务暂时作为后续可选模块。认证层只定义 `Authenticator`、`Principal` 和路由保护中间件,具体 JWT、Session 或 OAuth 由项目实现。核心数据库层只依赖 `database/sql`,具体驱动、迁移和表结构由项目选择。 当前成熟度与后续验收标准见 [ROADMAP.md](ROADMAP.md),版本变更见 [CHANGELOG.md](CHANGELOG.md)。