当我们的代码是有访问网络相关的操作时,比如http请求或者访问远程数据库,经常可能会发生一些错误,有些错误可能重新去发送请求就会成功,本文分析常见可能需要重试的场景,并最后给出python代码实现。

常见异常分成两种,一种是请求传输过程出错,另一种是服务端负载过高导致错误。
  对于第一种错误,可能请求还未到服务端处理程序就已经返回。
  HTTP请求错误:

  • DNSError:域名不能解析出ip地址,可能是服务端重新部署到其它地方。
  • ConnectionError:请求建立握手连接的过程出错,可能是请求时的网络质量比较差。

访问数据库错误:

  • OperationalError:与数据库服务器的连接丢失或连接失败时。比如访问PostgreSQL返回码
 Class 08 — Connection Exception
08000 connection_exception
08003 connection_does_not_exist
08006 connection_failure
08001 sqlclient_unable_to_establish_sqlconnection
08004 sqlserver_rejected_establishment_of_sqlconnection
  • ProtocolError:属于Redis中的一种常见错误, 当Redis服务器收到一个字节序列并转换为无意义的操作时,会引发异常。由于您在部署之前测试了软件,因此编写错误的代码不太可能发生错误。可能是传输层出现了错误。

对于第二类错误,服务器负载过高导致。对于HTTP请求,可根据状态码识别:

  •   408 Request Timeout: 当服务器花费很多时间处理您的请求而不能在等待时间返回。可能的原因:资源被大量传入请求所淹没。一段时间后等待和重试可能是最终完成数据处理的好策略。
  • 429 Too Many Requests: 在一段时间内发送的请求数量超过服务器允许的数量。服务器使用的这种技术称为速率限制。良好的服务端应该返回Retry-After标头,它提供建议在下一个请求之前需要等待多长时间。
  • 500 Internal Server Error: 这是最臭名昭着的HTTP服务器错误。错误原因多样性,对于发生的所有未捕获的异常,都返回这种错误。对于这种错误,应了解背后的原因再决定是否重试。
  • 503 Service Unavailable:由于临时过载,服务当前无法处理请求。经过一段时间的推迟,能得到缓解。
  • 504 Gateway Timeout:类似于408请求超时,网关或反向代理不能及时从上游服务器得到响应。

对于数据库访问:

  • OperationalError. 对于PostgreSQL和MySQL,它还包括不受软件工程师控制的故障。例如:处理期间发生内存分配错误,或无法处理事务。我建议重试它们。
  • IntegrityError: 当违反外键约束时可以引发它,例如当您尝试插入依赖于记录B的记录A时。由于系统的异步性质,可能还没有添加记录B.在这种情况下,进行重试。另一方面,当您尝试添加记录导致重复唯一键时,也会引发这种异常,这种情况下不需要重试。那么如何去识别这种情况,DBMS能返回状态码,假如mysql驱动能在状态码和异常类之间映射,就能识别这种需要重试的场景,在python3中,库pymysql可以在数据库返回码和异常之间映射。地址如下:

constants for MySQL errors
      the mapping between exception types in PyMYSQL and error codes.

本文以网络IO为例,利用python装饰器实现重试机制。用fetch函数去发送http请求下载网页

# Example is taken from http://aiohttp.readthedocs.io/en/stable/#getting-started
import aiohttp
import asyncio async def fetch(session, url):
async with session.get(url) as response:
return await response.text() # Client code, provided for reference
async def main():
async with aiohttp.ClientSession() as session:
html = await fetch(session, 'http://python.org')
print(html) loop = asyncio.get_event_loop()
loop.run_until_complete(main())

fetch函数并不是可靠的服务,可能存在失败的情况,这时候根据上文所列的情况实现重试机制,代码如下:

import aiohttp
@retry(aiohttp.DisconnectedError, aiohttp.ClientError,
aiohttp.HttpProcessingError)
async def fetch(session, url):
async with session.get(url) as response:
return await response.text()

retry实现如下,利用装饰器模式

import logging

from functools import wraps

log = logging.getLogger(__name__)

def retry(*exceptions, retries=3, cooldown=1, verbose=True):
"""Decorate an async function to execute it a few times before giving up.
Hopes that problem is resolved by another side shortly. Args:
exceptions (Tuple[Exception]) : The exceptions expected during function execution
retries (int): Number of retries of function execution.
cooldown (int): Seconds to wait before retry.
verbose (bool): Specifies if we should log about not successful attempts.
""" def wrap(func):
@wraps(func)
async def inner(*args, **kwargs):
retries_count = 0 while True:
try:
result = await func(*args, **kwargs)
except exceptions as err:
retries_count += 1
message = "Exception during {} execution. " \
"{} of {} retries attempted".
format(func, retries_count, retries) if retries_count > retries:
verbose and log.exception(message)
raise RetryExhaustedError(
func.__qualname__, args, kwargs) from err
else:
verbose and log.warning(message) if cooldown:
await asyncio.sleep(cooldown)
else:
return result
return inner
return wrap

基本思想是在达到重试次数限制之前捕获预期的异常。在每次执行之间,等待固定时间。此外,如果我们想要详细,会写每个失败尝试的日志。当然,本例子只提供了几个重试选项,一个完备的重试库应该提供更多重试配置,比如指数退避时间、根据返回结果重试等,这里推荐几个第三方库:

本文翻译自

Never Give Up, Retry: How Software Should Deal with Failures

下一篇博文将通过分析retrying源码来深入分析重试机制的实现原理。

retry重试常见场景及实现的更多相关文章

  1. [oracle]TX行锁发生的常见场景(转贴)

    TX行锁发生的常见场景: 1.当前会话要更新或删除的记录,已经被其他会话更新或删除. 2.对于表上有唯一索引的情况,多个会话插入或更新为相同的键值. 3.对于表上有位图索引的情况,多个会话即使更新不同 ...

  2. JVM之调优及常见场景分析

    JVM调优 GC调优是最后要做的工作,GC调优的目的可以总结为下面两点: 减少对象晋升到老年代的数量 减少FullGC的执行时间 通过监控排查问题及验证优化结果,可以分为: 命令监控:jps.jinf ...

  3. 使用IDEA模拟git命令使用的常见场景

    目录 使用IDEA模拟git命令使用的常见场景 前期准备 新建一个远程仓库 在一个文件夹内建立两个子文件夹作为两个本地仓库的存放位置 本地仓库与远程仓库建立联系 模拟两个用户协同开发的场景(使用IDE ...

  4. disruptor笔记之六:常见场景

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  5. MySQL索引失效的常见场景

    当然请记住,explain是一个好习惯! MySQL索引失效的常见场景 在验证下面的场景时,请准备足够多的数据量,因为数据量少时,MySQL的优化器有时会判定全表扫描无伤大雅,就不会命中索引了. 1. ...

  6. 京东云开发者|京东云RDS数据迁移常见场景攻略

    云时代已经来临,云上很多场景下都需要数据的迁移.备份和流转,各大云厂商也大都提供了自己的迁移工具.本文主要介绍京东云数据库为解决用户数据迁移的常见场景所提供的解决方案. 场景一:数据迁移上云 数据迁移 ...

  7. C# Retry重试操作解决方案(附源码)

    一.前言 (1)对于Thread的Abort方法,如果线程当前正在执行的是一段非托管代码,那么CLR就不会抛出ThreadAbortException,只有当代码继续回到CLR中时,才会引发Threa ...

  8. 自己动手实践 spring retry 重试框架

    前序 马上过年了,预祝大家,新年快乐,少写bug 什么是spring retry? spring retry是从spring batch独立出来的一个能功能,主要实现了重试和熔断. 什么时候用? 远程 ...

  9. Spring Retry 重试

    重试的使用场景比较多,比如调用远程服务时,由于网络或者服务端响应慢导致调用超时,此时可以多重试几次.用定时任务也可以实现重试的效果,但比较麻烦,用Spring Retry的话一个注解搞定所有.话不多说 ...

随机推荐

  1. docker部署pinpoint

    pinpoint-collector部署 Dockerfile FROM tomcat8:jdk8 MAINTAINER limugen<limugen@uce.cn> ENV APP_H ...

  2. JavaScript -DOM 编程艺术 2nd 完

    今日看完了这本书,做完了最后一个综合性例子.说实话收获良多,终于明白前端-h5 具体做什么 越学习越无知,这个看来真是一个真理. 后期计划: 1.CSS + DIV 布局深入了解,重点实战 2.Jav ...

  3. redis_字符串对象

    Redis总共支持五种数据类型:string,hash,list,set及zset.这里介绍字符串类型的实现 首先了解字符串对象的结构 // redis对象内存分配,列出主要相关的属性 redisOb ...

  4. Codeforces Codeforces Round #484 (Div. 2) E. Billiard

    Codeforces Codeforces Round #484 (Div. 2) E. Billiard 题目连接: http://codeforces.com/contest/982/proble ...

  5. [swarthmore cs75] Compiler 4 – Diamondback

    课程回顾 Swarthmore学院16年开的编译系统课,总共10次大作业.本随笔记录了相关的课堂笔记以及第6次大作业. 函数声明 增加函数声明.函数调用的抽象语法:在转换成anf之前还要检查函数声明和 ...

  6. U-Boot Makefile分析(1)配置脚本mkconfig分析

    我们在编译U-Boot之前,需要根据当前使用的板子进行配置,例如make s5p_goni_config,接着才能进行编译make.下面首先分析配置阶段U-Boot做了哪些事情. 由于执行这些命令是在 ...

  7. Django积木块七——视频

    视频 # 在网上搜索video.js然后下载相关的js和css文件,看文档正确使用视频模块,添加视频外链 <div style="width: 1200px;height: 675px ...

  8. 补发————DOM与BOM

    什么是Dom? DOM是w3c(万维网联盟)的标准. DOM定义了HTML与ML文档的标准: w3c文档对象模型(DOM)是中立于平台与语言的接口,他允许程序和脚本动态访问和更新文档的内容.结构和样式 ...

  9. MIPS汇编指令集

    MIPS有三种指令格式: R型 6 5 5 5 5 6 op rs rt rd shamt funct 功能:寄存器-寄存器ALU操作 (算术运算,逻辑运算) I型 6 5 5 16 op rs rt ...

  10. 前端框架本质之探究——以Vue.js为例

    问:我们在使用Vue时,实际上干了什么?   答:实际上只干了一件事——new了一个Vue对象.后面的事,都交由这个对象自动去做.就好像按了下开关,机器跑起来了,剩下的事就不用我们再操心了.   各位 ...