Go实现延期结果处理DeferredResult

简介

学过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的逻辑了,可以当作长轮训功能使用


欢迎关注,学习不迷路!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/147852.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ESP32 Arduino实战协议篇-搭建独立的 Web 服务器

在此项目中,您将创建一个带有 ESP32 的独立 Web 服务器,该服务器使用 Arduino IDE 编程环境控制输出(两个 LED)。Web 服务器是移动响应的,可以使用本地网络上的任何浏览器设备进行访问。我们将向您展示如何创建 Web 服务器以及代码如何逐步工作。 项目概况 在直接进入项目…

在线预览excel,luckysheet在vue项目中的使用

一. 需求 需要在内网项目中在线预览excel文档&#xff0c;并可以下载 二.在项目中下载并引入luckysheet 1.打开项目根目录&#xff0c;npm i luckyexcel 安装 npm i luckyexcel2.在项目的index.html文件中引入依赖 外网项目中的引入&#xff08;CDN引入&#xff09;&#…

Facebook内容的类型

随着人们日益依赖的社交媒体来进行信息获取与交流&#xff0c;Facebook作为全球最大的社交媒体平台之一&#xff0c;那么Facebook的内容都有哪些类型呢&#xff1f;下面小编来讲讲吧&#xff01; 1、实时发生的事 我们需要实时了解时事动态&#xff0c;这样可以使用户对品牌发…

003 OpenCV filter2D

目录 一、环境 二、图像卷积 三、代码演示 3.1、锐化 3.2、sobel边缘&#xff0c;x方向 3.3、sobel边缘&#xff0c;y方向 3.4、高斯模糊 3.5、完整代码 一、环境 本文使用环境为&#xff1a; Windows10Python 3.9.17opencv-python 4.8.0.74 二、图像卷积 在OpenCV…

聊聊近些年 CPU 在微架构、IO 速率上的演进过程

大家好&#xff0c;我是飞哥&#xff01; 在上一篇《深入了解 CPU 的型号、代际架构与微架构》 中我们介绍了我手头的一颗 Intel(R) Core(TM) i5 的型号规则&#xff0c;以及它的物理硬件的 Die 图结构。以及它对应的 Skylake 核的微架构实现。 不少同学开始问我其它型号的 CPU…

中移链共识机制介绍

01 为什么需要共识 共识是对某事达成的共同看法&#xff0c;它是区块链的灵魂&#xff0c;对确保区块链的完整性和安全性起着至关重要的作用。在传统的集中式系统中&#xff0c;单个实体或一组实体有权验证和记录交易。然而&#xff0c;区块链中的一个核心概念是去中心化&…

4、FFmpeg命令行操作8

生成测试文件 找三个不同的视频每个视频截取10秒内容 ffmpeg -i 沙海02.mp4 -ss 00:05:00 -t 10 -codec copy 1.mp4 ffmpeg -i 复仇者联盟3.mp4 -ss 00:05:00 -t 10 -codec copy 2.mp4 ffmpeg -i 红海行动.mp4 -ss 00:05:00 -t 10 -codec copy 3.mp4 如果音视…

Python基础入门例程61-NP61 牛牛的矩阵相加(循环语句)

最近的博文: Python基础入门例程60-NP60 跳过列表的某个元素(循环语句)-CSDN博客 Python基础入门例程59-NP59 提前结束的循环(循环语句)-CSDN博客 Python基础入门例程58-NP58 找到HR(循环语句)-CSDN博客 目录 最近的博文: 描述

整理低秩的理解

秩的定义是矩阵中非零特征值的个数。比如一个NxN的矩阵&#xff0c;它的秩为r&#xff0c;r远小于N&#xff0c;我们可以说它是低秩的。 但还有另一种情况&#xff1a;这个矩阵的的秩接近N&#xff0c;但它的特征值大多数接近于0&#xff0c;只有少数几个特征值特别大&#xf…

【DevOps】Git 图文详解(四):Git 使用入门

Git 图文详解&#xff08;四&#xff09;&#xff1a;Git 使用入门 1.创建仓库2.暂存区 add3.提交 commit 记录4.Git 的 “指针” 引用5.提交的唯一标识 id&#xff0c;HEAD~n 是什么意思&#xff1f;6.比较 diff 1.创建仓库 创建本地仓库的方法有两种&#xff1a; 一种是创建…

智能告警:如何通过监控易实现精准故障预警与快速定位

在动态变化的IT环境中&#xff0c;故障预防与快速响应成为了运维管理的关键。监控易作为一体化运维监控平台&#xff0c;凭借其智能告警和精准定位的特性&#xff0c;为运维团队提供了强有力的支持&#xff0c;确保了IT系统的稳定运行。本文将深入探讨监控易在故障预警和快速定…

LoRA低秩微调技术详解

在当今快节奏的技术环境中&#xff0c;大型AI模型正在推动不同领域的突破。 然而&#xff0c;根据特定任务或数据集定制这些模型可能是一项计算和资源密集型工作。 LoRA是一种突破性且高效的微调技术&#xff0c;它利用这些高级模型的强大功能来执行自定义任务和数据集&#xf…

单元测试实战(一)Controller 的测试

为鼓励单元测试&#xff0c;特分门别类示例各种组件的测试代码并进行解说&#xff0c;供开发人员参考。 本文中的测试均基于JUnit5。 单元测试实战&#xff08;一&#xff09;Controller 的测试 单元测试实战&#xff08;二&#xff09;Service 的测试 单元测试实战&…

ForkLift:macOS文件管理器/FTP客户端

ForkLift 是一款macOS下双窗口的文件管理器&#xff0c;可以代替本地的访达。ForkLift同时具备连接Ftp、SFtp、WebDav以及云服务器。 ForkLift还具备访达不具备的小功能&#xff0c;比如从文件夹位置打开终端&#xff0c;显示隐藏文件&#xff0c;制作替换等功能。ForkLift 是一…

Spring Cloud学习(九)【Elasticsearch 分布式搜索引擎01】

文章目录 初识 elasticsearch了解 ES倒排索引ES 的一些概念安装es、kibana安装elasticsearch部署kibana 分词器安装IK分词器ik分词器-拓展词库 索引库操作mapping 映射属性索引库的 CRUD 文档操作添加文档查看、删除文档修改文档Dynamic Mapping RestClient 操作索引库什么是Re…

代码随想录二刷 | 数组 | 移除元素

代码随想录二刷 &#xff5c; 数组 &#xff5c; 移除元素 题目描述解题思路 & 代码实现暴力解法双指针法 题目描述 27. 移除元素 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用…

【数据结构】F:B DS图_课程表 拓扑排序实现

F : B DS图_课程表 Description 小明这个学期必须选修n门课程&#xff0c;课程编号记为0到n-1。 在选修某些课程之前需要一些先修课程。先修课程按数组prerequisites给出&#xff0c;其中prerequisites[i] [a, b]&#xff0c;表示如果要学习课程a则必须先学习课程b。 例如&a…

Ubuntu/Debian Hat 系 Linux 使用

目录 1. Ubuntu/Debian Hat 系 Linux 使用1.1. 包1.1.1. Install Package1.1.2. Convert .rpm package to .deb1.1.3. Install RPM Package Directly Onto the System on Ubuntu1.1.4. Command not found 1. Ubuntu/Debian Hat 系 Linux 使用 1.1. 包 1.1.1. Install Package…

手搓哈希表、列表、队列,只为了用C语言快速求解华容道游戏,我不是大佬,只是一个游戏算法爱好者

背景 多年前曾经写过C语言求解华容道&#xff0c;当时没有用到哈希表&#xff0c;导致整个查重搜索数组过大&#xff0c;每次求解都得花上数分钟的时间&#xff0c;如今时过境迁&#xff0c;对数据结构和算法有了更深的理解&#xff0c;所以得把这一块补上了。(其实就是最近想…

Redis面经

Redis使用场景 1、缓存&#xff1a; 缓存三兄弟(穿透、击穿、雪崩) 、双写一致、持久化、数据过期策略&#xff0c;数据淘汰策略 2、分布式锁 setnx、redisson 3、消息队列 4、延迟队列 何种数据类型&#xff08;list、zset&#xff09; 缓存三兄弟 缓存穿透 缓存穿透…