Go实现超时控制

应用场景

交易、金融等事务系统往往会有各种下游,绝大多数时候我们会以同步方式进行访问,如调用RPC、HTTP等。 这些下游在通常延时相对稳定,但有时可能出现极端的超大延时,这些极端case可能具备特定的业务特征,也有可能单纯是硬件、网络的问题造成,最终表现在系统P99或者P999的延时出现了突刺,如果是面向C端的场景,也会向用户报出一些系统错误,造成用户体验的下降。 一种简易的解决方案是,针对关键的下游节点增加超时控制。在特定时间内,如果下游到期还未返回,不再暴露系统级错误,而是做特殊化处理,比如返回「处理中」状态。

Go实现方案

设计一个方法,使用闭包,传入时间和执行的任务,如果任务执行完未到时间,则直接返回,否则通知调用者超时。 为了保证代码简介和使用简单,我们仅定义一个Wrapper方法,方法定义如下 func TimeoutControlWrapper(duration time.Duration, fn func()) (timeout bool)

官方包time有一个After方法,可以在指定时间内,返回一个channel,基于此来判断是否超时。 另外,在Wrapper方法里异步化执行目标方法,执行完成后写入一个finish信号通知。 同时监听这两个channel,判断是否超时,代码如下

go 复制代码
func TimeoutControlWrapper(duration time.Duration, fn func()) (timeout bool) {
        finish := make(chan struct{})
        go func() {
                fn()
                finish <- struct{}{}
        }()

        select {
        case <-finish:
                return false
        case <-time.After(duration):
                return true
        }
}

结合场景,假设系统会调用一个支付系统的接口,接口本身延时不稳定,因此我们套用TimeoutControlWrapper

go 复制代码
func CallPaymentSystem(param PayParam) (payStatus PayStatus) {
    var payStatus PayStatus
    timeout := TimeoutControlWrapper(time.Second, func() {
        payStatus = PaymentSystemRPC.Pay(param)
    })
    if timeout {
        warn()    // WARN告警
        return  PROCESSING  // 返回处理中
    }
    return payStatus
}

延伸思考

上述通过一个简单的Wrapper,来实现调用下游时的超时控制。但在引入的场景里,实现上是不严谨的。哪怕不增加超时控制,我们也无法确认请求是否真实到达了下游系统,这本质上是一个分布式事务的问题,需要我们设计更加健全的系统能力保证一致性,比如通过消息的方式、补偿机制、增加对账系统。

相关推荐
下次一定x4 小时前
深度解析 Kratos 客户端服务发现与负载均衡:从 Dial 入口到 gRPC 全链路落地(下篇)
后端·go
乐茵lin10 小时前
大厂都在问:如何解决map的并发安全问题?三种方法让你对答如流
开发语言·go·编程·map·并发安全·底层源码·sync.map
不会写DN1 天前
GORM 实战入门:从环境搭建到企业级常用特性全解析
sql·mysql·go·gin
F1FJJ1 天前
Shield CLI 的 PostgreSQL 插件 v0.5.0 发布:数据库导出 + 协作增强,ER 图全新体验
网络·数据库·docker·postgresql·go
liangbm33 天前
AI-ViewNote:把网课和会议视频自动卷成结构化笔记
ai·typescript·go·软件构建·开源软件·react·桌面软件
我叫黑大帅3 天前
Gin 实战入门:从环境搭建到企业级常用特性全解析
后端·面试·go
我叫黑大帅3 天前
Gin 日志体系详解
后端·面试·go
F1FJJ3 天前
Shield CLI v0.3.3 新增 PostgreSQL 插件:浏览器里管理 PG 数据库
网络·网络协议·docker·postgresql·容器·go
mCell4 天前
【万字长文】从 AI SDK 到 mini-opencode:一次很巧的 Go Agent 架构实践
架构·go·agent
jump_jump4 天前
深入理解 Go Context:从原理到实战(基于 Go 1.26)
go·源码