曹大带我学 Go(7)—— 如何优雅地指定配置项
你好,我是小X。
曹大最近开 Go 课程了,小X 正在和曹大学 Go。
这个系列会讲一些从课程中学到的让人醍醐灌顶的东西,拨云见日,带你重新认识 Go。
最近一个年久失修的库导致了线上事故,不得不去做一些改进。
这个陈年库的作用是调用第三方的 RPC 拿一些比较重要的配置,业务代码中有段逻辑会根据读到的配置调用不同端的下游。如果没拿到配置,就会默认地调一个兜底下游。恰好这个兜底下游最近新上了一些逻辑,不兼容这种跨端调用,直接把它打挂了。
先抛开这个下游不健壮不谈,假设它是健壮的。
陈年库的问题在于:进程启动时它会去调一个下游拿数据,之后会定时更新。但如果启动时调用失败就直接 panic 了,所以之后也不会定时更新。理论上这个也没什么问题,服务在初始化时如果检测到了库的 panic,进程退出,重启就好了。
但是阻塞启动是比较危险的,所以有些服务就会吞掉 panic。于是,整个进程生命周期内这个配置就一直是缺失的状态。
因为阻塞服务的启动风险太高,所以当前的状态是把 panic recover 住了,但是之后这个配置也就一直没有更新的机会了。而陈年库其实是可以在后台静默更新数据的。
因此我要对陈年库要做一点改进:如果初始化时拉取配置失败,不 panic,后台静默修复。这个设置要在调用 Init 函数时设置,因为库就暴露了 Init 和 Get 函数。
但因为这个库有很多使用方,所以不可能更改函数签名和现在的行为,否则影响其他人使用。万一有业务都对这个是强依赖,就是要感知 panic,初始化失败就进程退出,你改了不就 gg 了。
我们知道,Go 语言里面有可变参数,调用它的时候可以不传实参,或者传多个实参。向陈年库函数的 Init 函数签名后加一个可变参数:
func Init(a int)
变成:
func Init(a int, opts ...optionFunc)
这样就不影响已有的用户了,并且我可以增加更多的设置项。这里的关键是 optionFunc
的实现原理是什么?
它其实是一个函数类型,它接受 options
结构体指针:
type optionFunc func(*options)
再定义一个 options 结构体用于放 bool 型变量 PanicWhenInitFail
,表示 Init 失败后是否 panic:
type options struct {PanicWhenInitFail bool
}
再来定义一个导出的函数,用户传入 bool 型变量就可以设置 options,而不用定义 options 对象。这种方法美妙的地方就在这里,要多次回味才能感受到:
func WithPanicWhenInitFail() optionFunc {return func(o *options) {o.PanicWhenInitFail = true}
}
初始时,Init 函数的实现如下:
func Init(a int) {fmt.Println(a)
}
修改后:
func Init(a int, opts ...optionFunc) {fmt.Println(a)var gOpt = &options{PanicWhenInitFail: false}for _, opt := range opts {opt(gOpt)}fmt.Println(gOpt)}
这样,main 函数就可以非常优雅地设置 PanicWhenInitFail
了:
func main() {Init(8)Init(8, WithPanicWhenInitFail())
}
不管加不加后面的配置,两种调用方式都可以编译成功,不会影响现有的用户,完美。
为什么这篇文章和曹大扯上关系,因为在曹大写的 mosn/homels[1] 这个库里也有类似的代码。当然,本文这种形式很常见,可以算作标配了。不过,有一点点不同之处,曹大定义了一个 interface,不过看起来感觉有点更难懂了。????
// Option holmes option type.
type Option interface {apply(*options) error
}type optionFunc func(*options) errorfunc (f optionFunc) apply(opts *options) error {return f(opts)
}
去 Google 上一查,其实这种形式,叫 Functional Options Pattern
,早在 2014 年 Rob Pike 就写过一篇博文[2]来说这个事,没几行代码,但是真的很优雅。
总结一下,当我们要修改已有的函数时,为了不破坏原有的签名和行为,可以使用 Functional Options Pattern
的形式增加可变参数,即可以增加设置项,又能兼容已有的代码。
好了,这就是今天全部的内容了~ 我是小X,我们下期再见~
欢迎关注曹大的 TechPaper 以及码农桃花源~
参考资料
[1]
mosn/homels: https://github.com/mosn/holmes
[2]
博文: https://commandcenter.blogspot.com/2014/01/self-referential-functions-and-design.html
曹大带我学 Go(7)—— 如何优雅地指定配置项相关推荐
- 『曹大带我学 Go 』系列文章汇总
你好,我是小 X. 之前写了 11 篇跟着曹大学 Go 的文章,今天来汇总一下. 曹大的功力深厚,但能学到多少全看自己.第一期 Go 训练营也早就结束了,但学习还得继续.后面我也会继续发布这个系列,希 ...
- 曹大带我学 Go(8)—— 一个打点引发的事故
你好,我是小X. 曹大最近开 Go 课程了,小X 正在和曹大学 Go. 这个系列会讲一些从课程中学到的让人醍醐灌顶的东西,拨云见日,带你重新认识 Go. 最近线上事故频发,搞得焦头烂额,但是能用上跟曹 ...
- 曹大带我学 Go(6)—— 技术之外
你好,我是小X. 曹大最近开 Go 课程了,小X 正在和曹大学 Go. 这个系列会讲一些从课程中学到的让人醍醐灌顶的东西,拨云见日,带你重新认识 Go. 有学员私下和我说,这个课程挺打击他的自信心.我 ...
- 曹大带我学 Go(2)—— 迷惑的 goroutine 执行顺序
你好,我是小X. 曹大最近开 Go 课程了,小X 正在和曹大学 Go. 这个系列会讲一些从课程中学到的让人醍醐灌顶的东西,拨云见日,带你重新认识 Go. 上一篇文章我们讲了 Go 调度的本质是一个生产 ...
- 曹大带我学 Go(12)—— 面向火焰图编程
你好,我是小X. 曹大最近开 Go 课程了,小X 正在和曹大学 Go. 这个系列会讲一些从课程中学到的让人醍醐灌顶的东西,拨云见日,带你重新认识 Go. 现实中听过各种面向 XX 编程,什么面向过程编 ...
- 曹大带我学 Go(11)—— 从 map 的 extra 字段谈起
你好,我是小X. 曹大最近开 Go 课程了,小X 正在和曹大学 Go. 这个系列会讲一些从课程中学到的让人醍醐灌顶的东西,拨云见日,带你重新认识 Go. 熟悉 map 结构体的读者应该知道,hmap ...
- 曹大带我学 Go(10)—— 如何给 Go 提性能优化的 pr
你好,我是小X. 曹大最近开 Go 课程了,小X 正在和曹大学 Go. 这个系列会讲一些从课程中学到的让人醍醐灌顶的东西,拨云见日,带你重新认识 Go. 之前 qcrao 写了一篇<成为 Go ...
- 曹大带我学 Go(9)—— 开始积累自己的工具库
你好,我是小X. 曹大最近开 Go 课程了,小X 正在和曹大学 Go. 这个系列会讲一些从课程中学到的让人醍醐灌顶的东西,拨云见日,带你重新认识 Go. 不知道你有没有这样的经验:看了很多计算机相关的 ...
- 曹大带我学 Go(5)—— 哪里来的 goexit
你好,我是小X. 曹大最近开 Go 课程了,小X 正在和曹大学 Go. 这个系列会讲一些从课程中学到的让人醍醐灌顶的东西,拨云见日,带你重新认识 Go. 在学员群里,有同学在用 dlv 调试时看到了令 ...
最新文章
- php ajax评论系统,Ajax / jQuery评论系统 - php
- asp.net mysql 读写分离_.NET Core实现分表分库、读写分离的通用 Repository功能
- OpenCVSharp_保存浮点型Mat数据
- Linux命令必知必会
- SpringBoot用JdbcTemplates访问Mysql
- 图片裁剪功能集成优化
- Android之水平ProgressBar多彩背景颜色
- 关闭word_Word文档如何快速查找?超实用的5个Word技巧教给你
- solr java浏览器访问_solr解决访问安全
- “洗净净”、“洗香香”、“洗爽爽” 京东又申请了这些商标
- VC中海量文件读写类设计与应用
- PDFLib去水印办法
- Modelica生态工具开发利器——MWorks.SDK 2.0
- idea继承后重新方法快捷键_idea 查看类继承关系的快捷键
- 皮尔森 统计学相关性分析_统计学之三大相关性系数(pearson、spearman、kendall)...
- Oracle的 wm_concat 的排序问题,Oracle的 listagg 函数
- USB组合设备——带鼠标功能的键盘
- 关于禅道二次开发的分享
- 快速搭建小程序,实现线上引流获客
- 用计算机搞音乐,用电脑键盘做音乐
热门文章
- 上传 录音_老罗推荐的是最好吗?AI旗舰录音笔对比评测
- vue 开发一个按钮组件
- 彻底卸载WinStdup
- shiro+redis多次调用doReadSession方法的解决方案
- 线程基础知识系列(三)线程的同步
- ASP.NET MVC 4 (一)路径映射
- 表现层(jsp)、持久层(类似dao)、业务层(逻辑层、service层)、模型(javabean)、控制层(action)...
- (转)JAVA AJAX教程第三章—AJAX详细讲解
- 使用 Apache Lucene 搜索文本——轻松为应用程序构建搜索和索引功能
- 联想B450系列安装XP且开启AHCI