你好,我是小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)—— 如何优雅地指定配置项相关推荐

  1. 『曹大带我学 Go 』系列文章汇总

    你好,我是小 X. 之前写了 11 篇跟着曹大学 Go 的文章,今天来汇总一下. 曹大的功力深厚,但能学到多少全看自己.第一期 Go 训练营也早就结束了,但学习还得继续.后面我也会继续发布这个系列,希 ...

  2. 曹大带我学 Go(8)—— 一个打点引发的事故

    你好,我是小X. 曹大最近开 Go 课程了,小X 正在和曹大学 Go. 这个系列会讲一些从课程中学到的让人醍醐灌顶的东西,拨云见日,带你重新认识 Go. 最近线上事故频发,搞得焦头烂额,但是能用上跟曹 ...

  3. 曹大带我学 Go(6)—— 技术之外

    你好,我是小X. 曹大最近开 Go 课程了,小X 正在和曹大学 Go. 这个系列会讲一些从课程中学到的让人醍醐灌顶的东西,拨云见日,带你重新认识 Go. 有学员私下和我说,这个课程挺打击他的自信心.我 ...

  4. 曹大带我学 Go(2)—— 迷惑的 goroutine 执行顺序

    你好,我是小X. 曹大最近开 Go 课程了,小X 正在和曹大学 Go. 这个系列会讲一些从课程中学到的让人醍醐灌顶的东西,拨云见日,带你重新认识 Go. 上一篇文章我们讲了 Go 调度的本质是一个生产 ...

  5. 曹大带我学 Go(12)—— 面向火焰图编程

    你好,我是小X. 曹大最近开 Go 课程了,小X 正在和曹大学 Go. 这个系列会讲一些从课程中学到的让人醍醐灌顶的东西,拨云见日,带你重新认识 Go. 现实中听过各种面向 XX 编程,什么面向过程编 ...

  6. 曹大带我学 Go(11)—— 从 map 的 extra 字段谈起

    你好,我是小X. 曹大最近开 Go 课程了,小X 正在和曹大学 Go. 这个系列会讲一些从课程中学到的让人醍醐灌顶的东西,拨云见日,带你重新认识 Go. 熟悉 map 结构体的读者应该知道,hmap ...

  7. 曹大带我学 Go(10)—— 如何给 Go 提性能优化的 pr

    你好,我是小X. 曹大最近开 Go 课程了,小X 正在和曹大学 Go. 这个系列会讲一些从课程中学到的让人醍醐灌顶的东西,拨云见日,带你重新认识 Go. 之前 qcrao 写了一篇<成为 Go ...

  8. 曹大带我学 Go(9)—— 开始积累自己的工具库

    你好,我是小X. 曹大最近开 Go 课程了,小X 正在和曹大学 Go. 这个系列会讲一些从课程中学到的让人醍醐灌顶的东西,拨云见日,带你重新认识 Go. 不知道你有没有这样的经验:看了很多计算机相关的 ...

  9. 曹大带我学 Go(5)—— 哪里来的 goexit

    你好,我是小X. 曹大最近开 Go 课程了,小X 正在和曹大学 Go. 这个系列会讲一些从课程中学到的让人醍醐灌顶的东西,拨云见日,带你重新认识 Go. 在学员群里,有同学在用 dlv 调试时看到了令 ...

最新文章

  1. php ajax评论系统,Ajax / jQuery评论系统 - php
  2. asp.net mysql 读写分离_.NET Core实现分表分库、读写分离的通用 Repository功能
  3. OpenCVSharp_保存浮点型Mat数据
  4. Linux命令必知必会
  5. SpringBoot用JdbcTemplates访问Mysql
  6. 图片裁剪功能集成优化
  7. Android之水平ProgressBar多彩背景颜色
  8. 关闭word_Word文档如何快速查找?超实用的5个Word技巧教给你
  9. solr java浏览器访问_solr解决访问安全
  10. “洗净净”、“洗香香”、“洗爽爽” 京东又申请了这些商标
  11. VC中海量文件读写类设计与应用
  12. PDFLib去水印办法
  13. Modelica生态工具开发利器——MWorks.SDK 2.0
  14. idea继承后重新方法快捷键_idea 查看类继承关系的快捷键
  15. 皮尔森 统计学相关性分析_统计学之三大相关性系数(pearson、spearman、kendall)...
  16. Oracle的 wm_concat 的排序问题,Oracle的 listagg 函数
  17. USB组合设备——带鼠标功能的键盘
  18. 关于禅道二次开发的分享
  19. 快速搭建小程序,实现线上引流获客
  20. 用计算机搞音乐,用电脑键盘做音乐

热门文章

  1. 上传 录音_老罗推荐的是最好吗?AI旗舰录音笔对比评测
  2. vue 开发一个按钮组件
  3. 彻底卸载WinStdup
  4. shiro+redis多次调用doReadSession方法的解决方案
  5. 线程基础知识系列(三)线程的同步
  6. ASP.NET MVC 4 (一)路径映射
  7. 表现层(jsp)、持久层(类似dao)、业务层(逻辑层、service层)、模型(javabean)、控制层(action)...
  8. (转)JAVA AJAX教程第三章—AJAX详细讲解
  9. 使用 Apache Lucene 搜索文本——轻松为应用程序构建搜索和索引功能
  10. 联想B450系列安装XP且开启AHCI