Golang 中强大的重试机制,解决瞬态错误

文章精选推荐

1 JetBrains Ai assistant 编程工具让你的工作效率翻倍
2 Extra Icons:JetBrains IDE的图标增强神器
3 IDEA插件推荐-SequenceDiagram,自动生成时序图
4 BashSupport Pro 这个ides插件主要是用来干嘛的 ?
5 IDEA必装的插件:Spring Boot Helper的使用与功能特点
6 Ai assistant ,又是一个写代码神器
7 Cursor 设备ID修改器,你的Cursor又可以继续试用了

文章正文

在 Go 语言中,处理瞬态错误(Transient Errors)是常见的挑战,尤其在网络请求、数据库操作、外部服务调用等场景中。瞬态错误通常是由于临时网络故障、资源竞争或服务不可用等原因引起的,这些错误可能会在一段时间后自动恢复。因此,重试机制在这些情况下非常重要。

Go 语言并没有提供内置的重试机制,但我们可以通过简单的控制结构和一些库来实现高效且灵活的重试机制。下面将介绍如何实现一个强大的重试机制来处理瞬态错误。

1. 基本重试实现

首先,介绍一个简单的重试实现,通过设置最大重试次数和每次重试的间隔时间。

基本重试机制的实现
package main

import (
	"fmt"
	"math/rand"
	"time"
)

// 模拟一个可能失败的操作
func unreliableOperation() error {
	// 模拟随机失败的情况
	if rand.Float32() < 0.7 {
		return fmt.Errorf("transient error")
	}
	return nil
}

// 重试逻辑
func retryOperation(retries int, delay time.Duration) error {
	var err error
	for i := 0; i < retries; i++ {
		err = unreliableOperation()
		if err == nil {
			return nil // 操作成功
		}

		// 打印错误并等待一段时间
		fmt.Printf("Retry %d/%d: %v\n", i+1, retries, err)
		time.Sleep(delay)
	}
	return fmt.Errorf("failed after %d retries: %w", retries, err)
}

func main() {
	rand.Seed(time.Now().UnixNano())

	// 尝试最多 5 次,每次重试间隔 1 秒
	err := retryOperation(5, time.Second)
	if err != nil {
		fmt.Println("Operation failed:", err)
	} else {
		fmt.Println("Operation succeeded")
	}
}
说明:
  • unreliableOperation():模拟一个可能失败的操作,每次调用有 70% 的概率失败。
  • retryOperation():重试操作函数,它会最多重试 retries 次,每次重试之间等待 delay 时间。如果超过最大重试次数,返回错误。
输出示例:
Retry 1/5: transient error
Retry 2/5: transient error
Retry 3/5: transient error
Retry 4/5: transient error
Operation failed: failed after 5 retries: transient error

2. 使用 github.com/cenkalti/backoff

为了更灵活、优雅地实现重试机制,Go 社区有一些优秀的第三方库。其中,backoff 库非常适合处理瞬态错误的重试。它提供了指数退避(Exponential Backoff)策略,这是在处理重试时常用的方式。

安装 backoff
go get github.com/cenkalti/backoff/v4
使用 backoff 库的实现
package main

import (
	"fmt"
	"github.com/cenkalti/backoff/v4"
	"math/rand"
	"time"
)

// 模拟一个可能失败的操作
func unreliableOperation() error {
	// 模拟随机失败的情况
	if rand.Float32() < 0.7 {
		return fmt.Errorf("transient error")
	}
	return nil
}

// 使用 backoff 重试操作
func retryOperationWithBackoff() error {
	// 设置指数退避策略,最大重试间隔为 10 秒
	bo := backoff.NewExponentialBackOff()
	bo.MaxElapsedTime = 30 * time.Second // 最大重试时间限制
	bo.MaxInterval = 10 * time.Second   // 最大间隔时间

	// 定义重试逻辑
	return backoff.Retry(func() error {
		err := unreliableOperation()
		if err != nil {
			return err // 如果操作失败,返回错误并重试
		}
		return nil // 操作成功
	}, bo)
}

func main() {
	rand.Seed(time.Now().UnixNano())

	err := retryOperationWithBackoff()
	if err != nil {
		fmt.Println("Operation failed:", err)
	} else {
		fmt.Println("Operation succeeded")
	}
}
说明:
  • 指数退避 (Exponential Backoff)backoff.NewExponentialBackOff() 创建了一个指数退避策略,重试间隔会逐渐增加。
  • 最大重试时间限制 (MaxElapsedTime):可以设置一个最大重试时长,超时后停止重试。
  • 最大间隔时间 (MaxInterval):可以限制每次重试的最大间隔时间。
输出示例:
Operation failed: transient error

在此示例中,重试会在失败时以指数级的时间间隔进行,直到成功或者达到最大重试次数为止。


3. 使用 github.com/avast/retry-go

另一个非常流行的库是 retry-go,它提供了简单的 API 来实现重试机制。此库支持自定义重试次数、延迟、间隔策略等。

安装 retry-go
go get github.com/avast/retry-go
使用 retry-go 库的实现
package main

import (
	"fmt"
	"github.com/avast/retry-go"
	"math/rand"
	"time"
)

// 模拟一个可能失败的操作
func unreliableOperation() error {
	// 模拟随机失败的情况
	if rand.Float32() < 0.7 {
		return fmt.Errorf("transient error")
	}
	return nil
}

// 使用 retry-go 重试操作
func retryOperationWithRetryGo() error {
	// 使用 retry-go 实现重试,最多重试 5 次,每次重试间隔 1 秒
	err := retry.Do(func() error {
		return unreliableOperation()
	}, retry.Attempts(5), retry.Delay(time.Second))

	return err
}

func main() {
	rand.Seed(time.Now().UnixNano())

	err := retryOperationWithRetryGo()
	if err != nil {
		fmt.Println("Operation failed:", err)
	} else {
		fmt.Println("Operation succeeded")
	}
}
说明:
  • retry.Do():执行传入的函数,如果该函数返回错误,将自动重试。
  • retry.Attempts():设置最大重试次数。
  • retry.Delay():设置每次重试之间的延迟时间。
输出示例:
Operation failed: transient error

4. 总结

基本实现:
  • 通过简单的循环、计数器和 time.Sleep() 实现的重试机制,适用于简单的场景。
  • 缺点是没有灵活的退避策略,也没有提供重试次数以外的更多配置选项。
使用 backoff 库:
  • 提供了指数退避机制,适用于需要更精细控制重试时间间隔的场景。
  • 支持最大重试时间、最大间隔时间等更多配置选项。
使用 retry-go 库:
  • 提供了非常简单易用的接口,能够快速实现重试。
  • 支持多种延迟策略和重试配置,适合快速开发。

根据不同的需求选择合适的库或实现方式。对于需要精细控制的场景,推荐使用 backoffretry-go 库;对于简单场景,基本的重试机制足够。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【GoLang】利用validator包实现服务端参数校验时自定义错误信息

在C/S架构下&#xff0c;服务端在校验请求参数时&#xff0c;若出现参数错误&#xff0c;要响应给客户端一个错误消息&#xff0c;通常我们会统一响应“参数错误”。 但是&#xff0c;如果只是一味的提示参数错误&#xff0c;我并不知道具体是哪个参数错了呀&#xff01;能不能…

机器学习 vs 深度学习

目录 一、机器学习 1、实现原理 2、实施方法 二、深度学习 1、与机器学习的联系与区别 2、神经网络的历史发展 3、神经网络的基本概念 一、机器学习 1、实现原理 训练&#xff08;归纳&#xff09;和预测&#xff08;演绎&#xff09; 归纳: 从具体案例中抽象一般规律…

Unity git版本管理

创建仓库的时候添加了Unity的.gitignore模版&#xff0c;在这个时候就能自动过滤不需要的文件 打开git bash之后&#xff0c;步骤git版本管理-CSDN博客 如果报错&#xff0c;尝试重新进git 第一次传会耗时较长&#xff0c;之后的更新就很快了

【JWT】jwt实现HS、RS、ES、ED签名与验签

JWT 实现 HS、RS、ES 和 ED 签名与验签 签名方式算法密钥类型签名要点验签要点HSHMAC-SHA256对称密钥- 使用 crypto/hmac 和对称密钥生成 HMAC 签名- 将 header.payload 作为数据输入- 使用同一密钥重新计算 HMAC 签名- 比较计算结果与接收到的签名是否一致RSRSA-SHA256公钥 …

【Bug 记录】el-sub-menu 第一次进入默认不高亮

项目场景&#xff1a; 项目场景&#xff1a;el-sub-menu 第一次进入默认不高亮 问题描述 例如&#xff1a;sub-menu 的 index 后端默认传过来是 number&#xff0c;我们需要手动转为 string&#xff0c;否则会有警告&#xff0c;而且第一次进入 sub-menu 默认不高亮。 解决方…

LLM幻觉(Hallucination)缓解技术综述与展望

LLMs 中的幻觉问题&#xff08;LLM 幻觉&#xff1a;现象剖析、影响与应对策略&#xff09;对其可靠性与实用性构成了严重威胁。幻觉现象表现为模型生成的内容与事实严重不符&#xff0c;在医疗、金融、法律等对准确性要求极高的关键领域&#xff0c;可能引发误导性后果&#x…

挖掘机的市场现状和发展前景:全球增长潜力,重塑基础设施建设新篇章

引言&#xff1a;工程机械的心脏&#xff0c;挖掘机的崛起之路 在现代化建设的浪潮中&#xff0c;挖掘机作为工程机械领域的核心设备&#xff0c;正以其强大的作业能力和广泛的应用场景&#xff0c;成为推动全球基础设施建设不可或缺的力量。从高速公路到大型矿场&#xff0c;…

算法每日双题精讲 —— 二分查找(山脉数组的峰顶索引,寻找峰值)

&#x1f31f;快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。 &#x1f31f; 别再犹豫了&#xff01;快来订阅我们的算法每日双题精讲专栏&#xff0c;一起踏上算法学习的精彩之旅吧&#x1f4aa; 在算法的…

Flutter_学习记录_基本组件的使用记录

1.TextWidge的常用属性 1.1TextAlign: 文本对齐属性 常用的样式有&#xff1a; TextAlign.center 居中TextAlign.left 左对齐TextAlign.right 有对齐 使用案例&#xff1a; body: Center(child: Text(开启 TextWidget 的旅程吧&#xff0c;珠珠, 开启 TextWidget 的旅程吧&a…

二叉树的存储(下)c++

链式存储 我们可以创建两个数组L[N]、r[N]&#xff0c;分别存储i 号结点的左右孩子的编号&#xff0c;这样就可以通过数组下标实现链式访问。 本质上还是孩子表示法&#xff0c;存储的是左右孩子的信息 #include <iostream>using namespace std;const int N 1e6 10; …

基于Docker的Kafka分布式集群

目录 1. 说明 2. 服务器规划 3. docker-compose文件 kafka{i}.yaml kafka-ui.yaml 4. kafka-ui配置集群监控 5. 参数表 6. 测试脚本 生产者-异步生产: AsyncKafkaProducer1.py 消费者-异步消费: AsyncKafkaConsumer1.py 7. 参考 1. 说明 创建一个本地开发环境所需的k…

Linux系统 C/C++编程基础——基于Qt的图形用户界面编程

ℹ️大家好&#xff0c;我是练小杰&#xff0c;今天周四了&#xff0c;距离除夕只有4天了&#xff0c;各位今年卫生都搞完了吗&#xff01;&#x1f606; 本文是接着昨天Linux 系统C/C编程的知识继续讲&#xff0c;基于Qt的图形用户界面编程概念及其命令&#xff0c;后续会不断…

C++11(二)

目录 左值引用与右值引用 左值引用 右值引用 右值与左值交叉引用 移动语义 移动构造 移动赋值 完美转发 本期我们将学习C11中比较重要的一个知识点------右值引用。 左值引用与右值引用 在学习左值引用和右值引用之前&#xff0c;我们得先知道什么是左值&#xff0…

【python】四帧差法实现运动目标检测

四帧差法是一种运动目标检测技术&#xff0c;它通过比较连续四帧图像之间的差异来检测运动物体。这种方法可以在一定的程度上提高检测的准确性。 目录 1 方案 2 实践 ① 代码 ② 效果图 1 方案 具体的步骤如下&#xff1a; ① 读取视频流&#xff1a;使用cv2.VideoCapture…

SpringBoot开发(二)Spring Boot项目构建、Bootstrap基础知识

1. Spring Boot项目构建 1.1. 简介 基于官方网站https://start.spring.io进行项目的创建. 1.1.1. 简介 Spring Boot是基于Spring4框架开发的全新框架&#xff0c;设计目的是简化搭建及开发过程&#xff0c;并不是对Spring功能上的增强&#xff0c;而是提供了一种快速使用Spr…

PMP–一、二、三模–分类–12.采购管理

文章目录 技巧十二、采购管理 一模12.采购管理--3.控制采购--输出--风险登记册--每个被选中的卖方都会带来特殊的风险。随着早期风险的过时以及新风险的出现&#xff0c;在项目执行期间对风险登记册进行变更。 供应商还未开始做&#xff0c;是一个风险&#xff0c;当做风险进行…

栈和队列(C语言)

目录 数据结构之栈 定义 实现方式 基本功能实现 1&#xff09;定义&#xff0c;初始化栈 2&#xff09;入栈 3&#xff09;出栈 4&#xff09;获得栈顶元素 5)获得栈中有效元素个数 6&#xff09;检测栈是否为空 7&#xff09;销毁栈 数据结构之队列 定义 实现方…

B站pwn教程笔记-1

因为没有垃圾处理机制&#xff0c;适合做编译&#xff0c;不会有堵塞 c语言市场占有率还是比较高的。 Windows根据后缀识别文件&#xff0c;linux根据文件头识别 55:16 编译过程 一步&#xff1a;直接gcc编译.c文件 这只是其中的一些步骤 gcc -S 转变为汇编。但其实这时候还…

jQuery小游戏

jQuery小游戏&#xff08;一&#xff09; 嘻嘻&#xff0c;今天我们来写个jquery小游戏吧 首先&#xff0c;我们准备一下写小游戏需要准备的佩饰&#xff0c;如果&#xff1a;图片、音乐、搞怪的小表情 这里我准备了一些游戏中需要涉及到的图片 游戏中使用到的方法 eval() 函…

Batch Normalization学习笔记

文章目录 一、为何引入 Batch Normalization二、具体步骤1、训练阶段2、预测阶段 三、关键代码实现四、补充五、参考文献 一、为何引入 Batch Normalization 现在主流的卷积神经网络几乎都使用了批量归一化&#xff08;Batch Normalization&#xff0c;BN&#xff09;1&#xf…