Files
go-omni/PROGRAM.md

6.4 KiB
Raw Blame History

通用 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 或模块依赖。