网站建设中什么是一栏,ftp客户端下载,海淀区城市建设档案馆网站,北京网站建设学习简介
学过java SpringBoot的同学应该知道#xff0c;有一个非常好用的类DeferredResult#xff0c;他可以设置一个超时时间#xff0c;如果在超时时间内有结果#xff0c;那么返回结果#xff0c;如果延期了#xff0c;返回预期设置的结果
说到这功能就会想到基于长轮训…简介
学过java SpringBoot的同学应该知道有一个非常好用的类DeferredResult他可以设置一个超时时间如果在超时时间内有结果那么返回结果如果延期了返回预期设置的结果
说到这功能就会想到基于长轮训实现的实时消息推送系统在很多基于spring的框架都用到了该功能在管理程序去做一个monitor监视某些数据的变化如果监视的数据有变动那么直接返回给请求者如果没有那么告诉请求者一个状态码让对方立刻重新请求
典型的例子有配置中心Apollo
实现
首先DeferredResult应该有这么几个关键属性 超时时间 timeout超时后的结果 timeoutResult正常结果result有了正常结果后应该做啥操作 resultHandler
代码实现如下 type DeferredResult struct {timeout time.Duration // 超时时间timeoutResult any // 超时结果预先定义resultHandler func(result any) // 结果处理回调done bool // 关闭result chan any // 设置正确结果
}func DeferredResultInstance(timeout time.Duration, timeoutResult any) *DeferredResult {deferred : DeferredResult{timeout: timeout,timeoutResult: timeoutResult,result: make(chan any),}return deferred
}func NewDeferredResult(timeout time.Duration, timeoutResult any, callback ...func(deferred *DeferredResult)) {instance : DeferredResultInstance(timeout, timeoutResult)if len(callback) 0 {go callback[0](instance)}instance.listener()
}func (deferred *DeferredResult) SetDeferredResultHandler(resultHandler func(result any)) {deferred.resultHandler resultHandler
}func (deferred *DeferredResult) SetResult(result any) error {if deferred.done {return errors.New(the deferred result is done)}deferred.result - resultreturn nil
}// 关键实现通过一个chan与Timer实现
func (deferred *DeferredResult) listener() {defer func() { deferred.done true }()timer : time.NewTimer(deferred.timeout)select {case result : -deferred.result:deferred.resultHandler(result)case -timer.C:deferred.resultHandler(deferred.timeoutResult)}
}测试
func TestDeferredResult_SetDeferredResultHandler(t *testing.T) {var result *DeferredResultNewDeferredResult(5*time.Second, 超时了, func(deferred *DeferredResult) {result deferredresult.SetDeferredResultHandler(func(result any) {log.Println(err)})time.Sleep(6 * time.Second)_ result.SetResult(success)})} RUN TestDeferredResult_SetDeferredResultHandler
deferred_test.go:15: 超时了
--- PASS: TestDeferredResult_SetDeferredResultHandler (5.00s)
PASS// 将time.Sleep(6 * time.Second)改成 4秒
// 等待4秒返回 RUN TestDeferredResult_SetDeferredResultHandler
deferred_test.go:15: success
--- PASS: TestDeferredResult_SetDeferredResultHandler (4.00s)
PASS扩展
以上对返回结果只是一个简单的打印如果我们的请求是一个http请求结果需要会写到ResponseWriter那么我们就需要有一个io.Writer去写于是进行扩展
扩展代码如下
ype DeferredResultWriter struct {*DeferredResultwrite io.Writer
}func NewDeferredResultWriter(timeout time.Duration, timeoutResult any, write io.Writer, callback ...func(deferred *DeferredResultWriter)) {deferred : DeferredResultWriter{DeferredResult: DeferredResultInstance(timeout, timeoutResult),write: write,}deferred.SetDeferredResultHandler(func(result any) {marshal, err : json.Marshal(result)if err ! nil {log.Println(err)}_, err deferred.write.Write(marshal)if err ! nil {log.Println(err)}})if len(callback) 0 {go callback[0](deferred)}deferred.listener()
}
扩展功能测试
type testHandler struct {
}func (test *testHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {var deferredResultWriter *DeferredResultWriterNewDeferredResultWriter(5*time.Second, 超时了, w, func(deferred *DeferredResultWriter) {deferredResultWriter deferredtime.Sleep(6 * time.Second)_ deferredResultWriter.SetResult(success)})}func TestNewHttpDeferredResult(t *testing.T) {http.Handle(/, testHandler{})_ http.ListenAndServe(:8000, nil)
}以上代码监听了一个8000的端口当访问8000端口时设置超时时间五秒请求会超时6秒那么五秒后会返回超时了
启动TestNewHttpDeferredResult使用curl请求测试一下
$ curl 127.0.0.1:8000
超时了## 设置为4秒
$ curl 127.0.0.1:8000
success总结
以上就是Go实现一个DeferredResult的逻辑了可以当作长轮训功能使用 欢迎关注学习不迷路