心得分享,如何组织入口文件

2023-01-16 22:11:01 +08:00
 Gota

这里讨论的是不用框架只用工具库( Toolkit )的情况,否则组织形式只能按照框架的规定,也就没什么讨论空间了。

其实同样的思路还可以用来组织具体的业务代码,整合第三方服务等不少场景。 这里先讲个大概,等过年回家之后再整理篇完整的博客。

入口部分主要是声明退出方式,然后开始初始化流程。

// cmd/app/main.go
package main

func main() {
	// 在第一次收到 SIG_INT ,SIG_TERM 时结束 Context ,
	// 第二次收到时 os.Exit()
	ctx, cancel := module.GracefulContext()
	defer cancel()

	// 执行业务逻辑
	if err := business.Run(ctx); err != nil {
		log.Fatalf("Error exit: %s", err)
	}
}

组装第一层程序结构,主要是:命令行,外部依赖,端口监听。 这里以常见的 HTTP 服务器为例。

// business/app.go
package business

type App struct {
	module.CLI    // 命令行
	module.SQLite // 数据库
	module.HTTP   // HTTP 服务
}

func Run(ctx context.Context) (err error) {
	var app App
	return module.Run(ctx, &app)
}

module.Run() 会依次初始化 App 中声明的每个 module ,然后运行所有实现了 Run() 的 module 。

初始化的大致流程为:module1.PreInit() -> module1.Init() -> module1.PostInit() -> module2.PreInit() -> ...

至于模块如何声明,就以 module.SQLite 为例:其中 Init()Close() 都是 module 的可选接口。 module.HTTP 还需要实现 Run()

// internal/module/sqlite.go
package module

type SQLite struct {
	DSN string
	DB  *sql.DB
}

func (m *SQLite) Init(ctx context.Context) (err error) {
	if m.DB, err = sql.Open("sqlite3", m.DSN); err != nil {
		return
	}

	ctx, cancel := context.WithTimeout(ctx, time.Second)
	defer cancel()

	return m.DB.PingContext(ctx)
}

func (m *SQLite) Close() error {
	return m.DB.Close()
}

module.HTTPmodule.CLI 代码比较长就不贴了,完整的 Demo 在 Github: https://github.com/GotaX/module-demo

有疑问或者想分享下自己是如何组织代码的也欢迎留言讨论。

1324 次点击
所在节点    Go 编程语言
1 条回复
dacapoday
2023-01-17 12:43:24 +08:00

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/909365

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX