快速开始:CLI
创建一个不启动 HTTP 的命令行或 worker 应用
Runa 不要求应用一定启动 HTTP。你可以只使用内核、配置、命令和 Module 生命周期,写一个命令行程序或后台进程。
创建项目
mkdir runa-cli-demo
cd runa-cli-demo
go mod init example.com/runa-cli-demo
go get github.com/duxweb/runa
写一个命令
创建 main.go:
package main
import (
"context"
"os"
"github.com/duxweb/runa"
"github.com/duxweb/runa/command"
)
type HelloCommand struct{}
func (HelloCommand) Name() string { return "hello" }
func (HelloCommand) Summary() string { return "输出一句问候" }
func (HelloCommand) Run(ctx context.Context, cmd *command.Context) error {
name := cmd.Get[string]("name", "runa")
return cmd.Println("hello", name)
}
func (HelloCommand) Flags(flags *command.FlagSet) {
flags.String("name", "runa", "要问候的名字")
}
func main() {
app := runa.New()
app.Command(HelloCommand{})
if err := app.Execute(context.Background(), os.Args[1:]); err != nil {
panic(err)
}
}
运行:
go run . hello
输出:
hello runa
带参数运行:
go run . hello --name Dux
输出:
hello Dux
这段代码做了什么
HelloCommand实现 Runa 命令接口Name()是命令名,也就是终端里输入的helloSummary()是命令说明,会显示在帮助信息里Flags(...)定义命令参数Run(...)是命令真正执行的逻辑app.Execute(..., os.Args[1:])把终端参数交给 Runa 命令系统
业务模块里注册命令
真实项目里,命令通常属于某个业务模块,比如用户同步、订单补偿、数据修复。
type AppModule struct {
provider.ModuleBase
}
func (AppModule) Name() string { return "app" }
func (AppModule) Register(ctx context.Context, app provider.Context) error {
return app.RegisterCommand(HelloCommand{})
}
注册模块:
app := runa.New()
app.Module(AppModule{})
if err := app.Execute(context.Background(), os.Args[1:]); err != nil {
panic(err)
}
Module 写法需要额外 import:
import (
"context"
"github.com/duxweb/runa/provider"
)
不传命令会发生什么
app.Run(ctx) 和 app.Execute(ctx, nil) 默认执行 serve 命令。没有安装任何 Host 时,通常用于内核启动检查或只运行命令的应用不需要这样做。
写真实 CLI 时,建议使用:
app.Execute(context.Background(), os.Args[1:])
这样用户输入什么命令,应用就执行什么命令。
需要后台进程时再接入能力
队列 worker、定时任务、WebSocket hub 这类长期运行的后台进程,通常通过对应能力包注册 Host。
初学时先掌握命令:
main.go -> app.Command(...) -> app.Execute(...)
哪些场景适合 CLI 模式
- 数据迁移工具
- 一次性数据修复命令
- 队列 worker 进程
- 定时任务进程
- 只需要配置、DI 和命令,不需要 HTTP 的后台服务
常见问题
go run . hello 和 go run . 有什么区别
go run . hello 会执行 hello 命令。go run . 没有传命令,会走默认命令。HTTP 应用通常默认是 serve,纯 CLI 应用建议显式传命令。
Flags 方法必须写吗
不必须。没有参数的命令可以不实现 Flags。
命令里怎么拿应用对象
可以通过 cmd.App() 取得当前应用对象。多数业务场景更推荐从 DI 或能力包的 Default() 获取需要的对象。