6.4 KiB
通用 Go 项目模板
从 v0.28.0-preview 起,project new/generate/check 提供不绑定协议与业务的工程骨架。默认只有配置、日志、依赖装配、生命周期和普通 Go 运行入口;不生成 .api、HTTP Handler、Swagger、业务任务,也不监听端口、连接数据库或队列。不增加第三方依赖。
创建与运行
go install git.yuntuo.hk/k2safe/go-omni/cmd/go-omni@v0.30.0-preview
go-omni project new demo --module example.com/demo
cd demo
go mod tidy
go run . -check-config
go run . # 默认等待 SIGINT / SIGTERM
go build -o program .
目标目录必须为空;未指定 module 时使用目录名。远程安装的 CLI 将自己的固定版本写入 go.mod,无本地替换。当前通用模板要求框架 v0.28.0-preview 或更新版本。源码开发可显式 --framework-dir /path/to/go-omni,不会从当前工作目录隐式选择本地框架。--framework-version 可指定兼容版本。框架版本、依赖更新由项目修改 go.mod,重新生成不会代为升级依赖。
常驻程序、一次性程序用同一份骨架:项目自己的 Run 决定何时完成。完整生成项目见 examples/program,不需要外部服务。
文件职责
| 路径 | 维护方与职责 |
|---|---|
main.go |
生成器:信号、启动、运行入口监督、退出状态与日志收尾 |
internal/config/loadGen.go |
生成器:统一配置加载 |
internal/svc/runtimeGen.go |
生成器:依赖初始化及失败收尾 |
internal/config/config.go |
项目:Config、Default、Validate;初始只含 log/lifecycle |
internal/config/loader.go |
项目:按需注册额外文件格式 |
etc/config.yaml |
项目:配置与显式环境引用 |
internal/svc/serviceContext.go |
项目:依赖字段、Init、资源与后台工作登记 |
internal/run/run.go |
项目:Run 的实际实现 |
go.mod、README、.gitignore、其他 Go 文件 |
项目:生成器不覆盖 |
.goOmni/projectManifest.json |
生成器:工程身份、模板版本、生成文件哈希;应提交 Git |
配置遵守 CONFIG.md:默认值 → 文件显式 ${NAME} / ${NAME:-fallback} → 类型绑定 → 校验,没有隐式环境覆盖。JSON/YAML/XML 内置;-config "" 只用默认值。-check-config 不打开日志文件、不初始化依赖、不调用 Run。日志通过独立实例传给 svc,并注入 Context/WorkContext;不替换进程级默认日志实例。
运行与退出
func Run(ctx context.Context, deps *svc.ServiceContext) error {
// 一次性程序可完成处理后直接 return nil。
// 常驻程序收到 ctx.Done() 后停止自己的主流程。
<-ctx.Done()
return nil
}
nil 表示正常完成,返回 error 表示运行失败。后台组件用 RequestShutdown(err) 报告致命故障,RequestShutdown(nil) 请求正常停止。框架不替项目重试、重新调度或重启任务。
依赖在 svc.Init 中装配:创建后立即用 OnClose 登记清理,后台组件同时登记同名 OnStop 和 OnDrain。所有登记应在 Init 返回前完成;Run 不得并发追加生命周期登记。组件何时接收工作由项目决定,停止后不得重新开始领取或启动未登记的工作。
Context()是提前停止通知,用来停止主流程或接收新工作。WorkContext()在正常排空期间仍有效,用于已接受的工作。OnStop停止接收新工作,不关闭处理中的工作仍依赖的资源。OnDrain返回 nil,必须意味着组件处理、确认和 defer 收尾均已结束。仅返回ctx.Err()不能证明结束。- 全部停止钩子先于全部排空钩子;同阶段并行。有先后依赖的组件在一个钩子内显式排序。
- 全部工作确认结束后,资源按
OnClose登记的反序释放,最后关闭入口拥有的日志。
生成入口自动监督 Run 本身,以 go-omni/project/run 保留名称登记完成屏障。收到信号、Run 返回或报告故障后开始收尾,同时等待 Run 及其他已登记工作。Run 不应等待资源关闭:资源关闭发生在 Run 完成之后。
初始化失败同样收尾已创建的资源和已启动的工作。Init/Run 内 panic 被转为失败,安全收尾后进程以非零状态退出;任意自建 goroutine 的 panic 仍由项目负责处理。Run 不响应取消或其他工作无法确认结束时,lifecycle.stopTimeout/drainTimeout/cancelTimeout 限定等待窗口,返回 ErrResourcesRetained,跳过共享资源和日志关闭,以失败状态退出。取消后的工作不能被 Go 强制终止,保留资源不代表工作已经完成。SIGKILL 和进程崩溃不会执行退出钩子。
详见 生命周期契约。现成组件必须按其真实停止/完成语义适配,不能把某个 Run/Close 返回直接视为业务结束。
生成检查与兼容
go-omni project generate --dry-run
go-omni project generate
go-omni project check # 等价于 project generate --check
go test ./...
生成器不执行项目 Go 代码、不下载依赖。check/预览只读,不创建锁文件;生成时使用独立项目锁、路径和哈希预检。生成文件被手工修改会报冲突,不提供强制覆盖。删除的生成文件可补回;缺失的项目所有文件必须显式恢复,避免把删除的业务文件当成空白骨架重建。
每个文件通过原子替换写入,普通写入失败回滚此前变更;整个目录不具备崩溃事务性。生成期间不要同时手工编辑。发现遗留 project.lock 时,先确认没有生成进程再手工移除。
check 检查模板漂移和必要文件,不检查业务正确性,也不能替代 Go 编译与测试。新的模板版本会重新生成受管文件;不自动合并项目所有文件或更新 go.mod。未知的新清单版本会要求使用兼容 CLI。
原有 new / api new 及 API 工程行为保留。通用工程使用自己的清单和命令,不能交给 api generate 或 add 转换;新增业务包直接写普通 Go。从 v0.29.0-preview 起,workspace generate/check 可以同时处理 API 与通用工程。清单可填写 kind: api | project,省略时按生成清单识别;format 对通用工程显示 SKIP。见 完整混合示例。各 module 仍独立,workspace 命令不维护 go.work 或模块依赖。