新提案:增加标准库 Context 的取消 API

大家好,我是煎鱼。

协程(Goroutine)是 Go 语言的一个大杀器,而我们常常需要在多个协程之间进行各种协调和通讯。

915c90805c5cdea1ef56191b241b4525.png
图来自 @Soham Kamani

所有 Go 有一个特别独特的东西,他就是上下文(context),你会在各种函数的第一个入参处见到他,标配了。

场景包含但不限于:

  • 依赖 context 传递公共的上下文信息。

  • 使用 goroutine 时进行异步操作,依赖 context 进行取消或返回错误等。

  • 依赖 context 进行跨协程的管理和控制。

背景

标准库 Context 的 API 有许许多多种,今天的主角是 Cancel(取消)行为。

5d006760c5464614d1e2fa12b34f1b78.png

在代码中的 API 调用,如下:

ctx, fn := context.WithCancel(ctx)

结合使用的案例来看,如下:

func operation1(ctx context.Context) error {
 time.Sleep(100 * time.Millisecond)
 return errors.New("failed")
}

func operation2(ctx context.Context) {
 select {
 case <-time.After(500 * time.Millisecond):
  fmt.Println("done")
 case <-ctx.Done():
  fmt.Println("halted operation2")
 }
}

func main() {
 ctx := context.Background()
 ctx, cancel := context.WithCancel(ctx)

 go func() {
  err := operation1(ctx)
  if err != nil {
   cancel()
  }
 }()

 operation2(ctx)
}

在上述程序中,当执行函数 operation1 后,假设返回了错误,就会执行 context.cancel 方法,将正在阻塞执行的 operation2 函数给结束掉。

这么来看,他是一个无比正常普通的 Go 程序。但这里有一个比较折腾的点,那就是你 cancel 取消了上下文后,只知道是被 cancel 了。原因是什么?

为什么被取消,没人知道...?

这就很苦恼了。我朋友在公司里经常看到这种案例,最后大家只能去翻日志或者根据蛛丝马迹去猜逻辑。

是比较不合理的。

新提案

在以前就有人提过类似 issues,就是想 “方便调试上下文被取消的地方”,也就是想解决被取消的场景处理。

经过几年的探讨后,@Sameer Ajmani 提出了新的提案《proposal: context: add APIs for writing and reading cancelation cause》来解决这个问题。

会新增如下几个新的 API:

package context

type CancelCauseFunc func(cause error)

func Cause(c Context) error

func WithDeadlineCause(parent Context, d time.Time, cause error) (Context, CancelFunc)

func WithTimeoutCause(parent Context, timeout time.Duration, cause error) (Context, CancelFunc)

使用案例:

ctx, cancel := context.WithCancelCause(parent)
cancel(myError)

ctx.Err() // returns context.Canceled
context.Cause(ctx) // returns myError

在调用 WithCancelCauseWithTimeoutCause 方法后,会返回一个 CancelCauseFunc,而不是 CancelFunc

其差异之处在于:可以通过传入对应的 Error 等类型的信息,然后在调用Cause 方法来获取其被取消的根因错误。

也就是既能得到被取消时的状态(context.Canceled),也能获取到对应的错误信息(myError),以此来解决前文中所提到的场景。

总结

这篇文章中,我们介绍了 Go 最常见的标准库 Context 的一个设计上的场景缺失。有 Context 状态码是不够的,在业务设计上,状态码和错误信息应该配套。

等该提案合并后,相信以往有过类似经历的同学,可以减少一定的排查时间了...

关注煎鱼,获取业内第一手消息和知识 👇

ba0f197ac2dca22595f0c77f0393aa8a.png

9506117f6baf9ed77607a2ea4bcbff98.png

你好,我是煎鱼,出版过 Go 畅销书《Go 语言编程之旅》,再到获得 GOP(Go 领域最有观点专家)荣誉,点击蓝字查看我的出书之路

日常分享高质量文章,输出 Go 面试、工作经验、架构设计,加微信拉读者交流群,和大家交流!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值