Golang之HTTP服务超时控制(二)
前情提要
因为上一篇提过,每次来一个请求,然后就会起一个goroutinue
那么导致的可能就是一个树形结构的请求图,底下节点在执行中如果发生了超时,那么就有协程会堆积,所以超时控制是有必要的,一般的实现都由一个顶层设计一个Context进行自顶向下传递,这样可以从一个地方去避免多处执行异常,对于Context的过多细节我不在这里一一阐述,有需要的我将单独出一篇关于Context的介绍,下面我们就来看一下源码是如何设计的:
Context
// Context's methods may be called by multiple goroutines simultaneously.
type Context interface {
// 当Context被取消或者到了deadline,返回一个被关闭的channel
Done() <-chan struct{
}
}
// 函数句柄
type CancelFunc func()
设计初衷最关注的两个点就是一个是如何主动结束下游,另一个是如何通知上游结束下游时
前者利用CancelFunc
后者利用Done
,后者需要不断监听所以利用channel的返回值做监听
//创建退出Context
func WithCancel(parent Context)(ctx Context,cancel CancelFunc){
}
//创建有超时时间的Context
func WithTimeout(parent Context,timeout time.Duration)(Context,CancelFunc){
}
//创建有截止时间的Context
func WithDeadline(parent Context,d time.Time)(Context,CancelFunc){
}
WithCancel/WithTimeout/WithDeadline
都是通过定时器来自动触发终结通知的,也就是说为父节点生成一个Done
的子节点,并且返回子节点的CancelFunc
函数句柄.
封装自定义的Context
context.go
可以定义一个自己的Context,里面先拥有最基本的request和response两个参数,最后是因为思考到并发写resposne的writer所以需要加入锁成员变量以及防止重复写的超时标志位
package framework
import (
"context"
"encoding/json"
"net/http"
"sync"
)
type Context struct {
Request *http.Request
ResponseWriter http.ResponseWriter
hasTimeOut bool // 是否超时标记位
writerMux *sync.Mutex
}
func NewContext()*Context{
return &Context{
}
}
func (ctx *Context) BaseContext() co