【Go知识点】如何重置 context.WithTimeout 超时时间但不丢失trace value?

4 篇文章 1 订阅
2 篇文章 0 订阅
文章介绍了在Go编程中,如何解决使用context.WithTimeout设定超时时间后,无法延长或重置超时时间的问题。通过go-zero库中的contextx.ValueOnlyFrom方法,可以在不丢失values的情况下重置超时时间。文中提供了一个测试示例,展示如何使用这个工具函数,并解释了其工作原理,涉及context的Deadline、Done和Err方法的改写。
摘要由CSDN通过智能技术生成

在这里插入图片描述

一、前言

我们在业务编程中常常会使用 context.WithTimeout 来对超时时间进行控制,来保障处理时效是在所控制的范围内,但对于Go原生的 context.WithTimeout 使用中存在一些限制,比如:超时时间只能改短不能改长或重置。

如果遇到在逻辑过程中使用goruntine来处理一个异步流程,context.WithTimeout应为接口超时设定了3秒,异步处理时间过长导致超时,想要给异步流程指定独立的timeout chatGPT给出的方法是通过 context.Background() 重新创建一个ctx。

但是这里会存在一个问题,就是context中的value会全部丢掉,比如里面存放的trace或者一些值将无法使用,把这个问题在给 chatGPT,它让通过WithValue挨个重新赋值…

本章就带给大家带来 chatGPT 也不知道的知识点,如何可以方便的重置 WithTimeout 又不丢失 value。

在这里插入图片描述

二、成熟的工具库"解君愁"

笔者一开始也不知道如何处理会比较好,感觉是一个通性问题就去问了下go-zero作者 万老师 ,给出了再go-zero中已经封装好的一个解法 contextx.ValueOnlyFrom

https://github.com/zeromicro/go-zero/blob/master/core/contextx/valueonlycontext.go

我们一起看下单测例子:


func Test_ValueOnlyFrom(t *testing.T) {

	ctx := context.Background()
	deadline, ok := ctx.Deadline()
	assert.Equal(t, ok, false) // 没有截止日期

	// 设置timeout
	ctx, cancel := context.WithTimeout(ctx, time.Second*3)
	defer cancel()
	deadline, ok = ctx.Deadline()
	assert.Equal(t, ok, true)                             // 有截止日期
	assert.Equal(t, deadline.Unix(), time.Now().Unix()+3) // 日期为当前时间 + 3秒

	// 超时时间改短(生效)
	ctx, cancel = context.WithTimeout(ctx, time.Second*1)
	defer cancel()
	deadline, ok = ctx.Deadline()
	assert.Equal(t, ok, true)                             // 有截止日期
	assert.Equal(t, deadline.Unix(), time.Now().Unix()+1) // 日期为当前时间 + 1秒

	// 超时时间改长(不生效)
	ctx, cancel = context.WithTimeout(ctx, time.Second*5)
	defer cancel()
	deadline, ok = ctx.Deadline()
	assert.Equal(t, ok, true)                             // 有截止日期
	assert.Equal(t, deadline.Unix(), time.Now().Unix()+1) // 日期为当前时间 + 1秒

	// 重置超时时间
	ctx = contextx.ValueOnlyFrom(ctx)
	deadline, ok = ctx.Deadline()
	assert.Equal(t, ok, false) // 没有截止日期

	// 超时时间改长(生效)
	ctx, cancel = context.WithTimeout(ctx, time.Second*5)
	defer cancel()
	deadline, ok = ctx.Deadline()
	assert.Equal(t, ok, true)                             // 有截止日期
	assert.Equal(t, deadline.Unix(), time.Now().Unix()+5) // 日期为当前时间 + 5秒

}

三、源码理解

其实原理挺简单测,context就是一个 type Context interface ,只需要将其中和WithTimeout有关的几个方法进行改写就可以了,通过 valueOnlyContext 结构体继承 context.Context 就继承了 Value 值,仅改写Deadline、Done和Err 就能达到重置 WithTimeout 的效果, 而不改写 Value 方法对应的值也就保留下来了。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

文振熙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值