zoukankan      html  css  js  c++  java
  • 一个python实现重试机制的简要实践

    最近在写接口测试脚本时,遇到如下一个测试场景

    1、A系统会创建一条数据,创建成功后会把数据推到B系统;

    2、由于是两个系统之间通信,数据不会立刻从A系统同步到B系统,中间有一个短暂的时间差;

    我要调试的接口有2个,一是在A系统调用一个接口,生成数据;二是在B系统调用另一个接口处理数据。

    实际操作后,发现一个问题:由于调用完A接口后,会立刻调用B接口,从代码层面看,这个时间差很短,虽然A系统已经把数据生成了,但在这么短时间内还没推送到B系统,导致调用B接口时,查不到这条数据,就会报错

    第一个解决方案

    开始想到的解决方案是使用time.sleep(),当调用A接口后,等待一段时间,如 time.sleep(5),死等5s,然后再调用B接口

    因为等待5s后,数据一般能够从A系统推送到B系统

    当然如果5s后还没有同步到B系统,调用B接口时仍然会报错,所以这并不是一个很好的解决方案

    第二个解决方案

    互联网冲浪一番后发现了python有一个库可以实现重试机制:tenacity

    下面是找到的一些参考博客,可以看一下基础用法:https://www.cnblogs.com/wuzhibinsuib/p/13443622.html

    接下来说一下自己的实验结果以及理解

    它的简单用法是给需要重试的代码加上@retry修饰器,代码抛出异常会被装饰器捕获并进行重试

    这里的关键是捕获到到代码抛出的异常

    例1【如果报错会一直重试】

    @retry
    def test_retry1():
        print("等待重试.....")
        raise Exception  # 通过raise直接返回一个错误
    
    @retry
    def test_retry2():
        print("等待重试.....")
        return "hello" + 1  # 人为制造一个错误,这里我是把字符串和整数相加,因为类型不同,肯定会报错,所以会触发重试

    上述2段代码运行后会一直打印“等待重试”,直至手工停止运行

    例2【设置最大重试次数stop_after_attempt】

    @retry(stop=stop_after_attempt(5))
    def test_retry():
        print("等待重试.....")
        return "hello" + 1 

    用 stop 接收 stop_after_attempt,当重试指定次数时,结束重试,如下重试了5次

    例3【设置最大重时间,如果失败,则重试,一直重试5s】 

    @retry(stop=stop_after_delay(5))
    def test_retry():
        print("等待重试.....")
        return "hello" + 1 

    例4【出现特定错误后重试】

    @retry(retry=retry_if_exception_type(TypeError))
    def test_retry1():
        print("等待重试.....")
        return "hello" + 1  # 捕获类型错误,当出现类型错误时重试
    
    @retry(retry=retry_if_exception_type(SyntaxError))
    def test_retry2():
        print("等待重试.....")
        raise SyntaxError  # 捕获语法错误,当出现语法错误时重试

    例5【满足自定义的条件后重试】

    # 首先定义了一个函数symbol,它的作用是判断传入的值是否为None;它返回一个布尔值,如果结果value=None,则返回true,否则返回False
    def symbol(value):
        return value is None
    
    
    # 装饰器中retry=retry_if_result(symbol),表示把test_retry函数的结果传入symbol,判断test_retry的结果是否为None,
    # 如果=None,就进行重试(retry),如果不等于None,就结束并返回函数值(所以达成重试的条件是test_retry的结果是否为条件函数定义的结果)
    @retry(stop=stop_after_attempt(3), retry=retry_if_result(symbol), reraise=True) def test_retry(): print("等待重试.....") return None
    symbol()函数是定义的条件函数,test_retry()函数是希望重试的函数,它俩通过装饰器中的retry_if_result()来关联,具体含义可以看下上述代码的注释

    接下来开始处理我的接口测试脚本,用到是上面例5的自定义条件重试

    首先处理需要重试的方法,我规定了当这个方法没有接收到推送过来的数据时,返回None

        def seal_regist(code):
    
            seal_data = self.get_seal_data(code)
    
            try:
                if seal_data["data"]["list"]:
    
                    r = requests.post(url, json=payload, headers=headers)
                    return r.json()
    
                else:
                    print("列表中没有这条待用印数据{},请检查系统~".format(code))
                    return None
    
            except Exception as e:
                raise e

    定义一个条件函数

    def test_retry(value):
        """重试条件函数"""
        return value is None

    给 seal_regist()函数加上retry装饰器

    @retry(stop=stop_after_delay(10), retry=retry_if_result(test_retry))
        def seal_regist(code):
          .....
          .....

    如果 seal_regist()返回None则重试,最大重试时间为10s

    ps.因为重试函数中需要用到登陆cookie,之前是把登陆获取cookie的方法写到里面的,但是如果加上重试机制的话,当开始重试时会一直重新登录获取cookie,提示登陆频繁并导致登陆接口调用失败,所以为了避免这种情况,我把获取登陆cookie的方法放到了外面,这样无论重试几次都用开始获取到的一个cookie即可(所以如果有遇到和我类似情况的,把那些类似只需获取一次数据的方法放到外面,避免重复请求接口引发异常)

  • 相关阅读:
    前nginx后Apache+Node反向代理
    JavaScript面试时候的坑洼沟洄——逗号、冒号与括号
    JavaScript面试时候的坑洼沟洄——表达式与运算符
    JavaScript面试时候的坑洼沟洄——数据类型
    容易被忽略CSS特性
    常用CSS优化总结——网络性能与语法性能建议
    quic-go测试
    golang证书认证通信
    golang爬虫
    websocket概述
  • 原文地址:https://www.cnblogs.com/hanmk/p/15525986.html
Copyright © 2011-2022 走看看