retrying-异常重复处理

from retrying import retry

@retry(stop_max_attempt_number=3, wait_fixed=2000)
# 遇到异常将重试-stop_max_attempt_number=3   最大重复次数
# wait_fixed = 2000    重复间隔等待睡眠时间
def get_data_uploading():
    url = 'http://192.168.0.12t'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'
    }
    print(headers[0])
    return
if __name__ == '__main__':
    get_data_uploading()

如上所见,默认行为是无需等待就永远重试。

@retry
def never_give_up_never_surrender():
    print "Retry forever ignoring Exceptions, don't wait between retries"

让我们少一点坚持,并设置一些界限,如放弃前的尝试次数。

@retry(stop_max_attempt_number=7)
def stop_after_7_attempts():
    print "Stopping after 7 attempts"

我们没有一整天的时间,所以让我们设定一个边界,我们应该重新尝试多久的东西。

@retry(stop_max_delay=10000)
def stop_after_10_s():
    print "Stopping after 10 seconds"

大多数事情不喜欢被调查得尽可能快, 所以让我们在重述之间等待 2 秒。

@retry(wait_fixed=2000)
def wait_2_s():
    print "Wait 2 second between retries"

有些东西在注射一点随机性时表现最好。

@retry(wait_random_min=1000, wait_random_max=2000)
def wait_random_1_to_2_s():
    print "Randomly wait 1 to 2 seconds between retries"

话又说回来, 在重试分布式服务和其他远程端点时, 很难击败指数级的后退。

@retry(wait_exponential_multiplier=1000, wait_exponential_max=10000)
def wait_exponential_1000():
    print "Wait 2^x * 1000 milliseconds between each retry, up to 10 seconds, then 10 seconds afterwards"

我们有一些选择来处理提出特定或一般例外的复述,如这里的案例。

def retry_if_io_error(exception):
    """Return True if we should retry (in this case when it's an IOError), False otherwise"""
    return isinstance(exception, IOError)

@retry(retry_on_exception=retry_if_io_error)
def might_io_error():
    print "Retry forever with no wait if an IOError occurs, raise any other errors"

@retry(retry_on_exception=retry_if_io_error, wrap_exception=True)
def only_raise_retry_error_when_not_io_error():
    print "Retry forever with no wait if an IOError occurs, raise any other errors wrapped in RetryError"

我们还可以使用函数的结果来改变重试的行为。

def retry_if_result_none(result):
    """Return True if we should retry (in this case when result is None), False otherwise"""
    return result is None

@retry(retry_on_result=retry_if_result_none)
def might_return_none():
    print "Retry forever ignoring Exceptions with no wait if return value is None"

任何停止,等待等的组合也支持给你的自由混合和匹配。

官方文档:重试 »皮皮 (pypi.org)

### Spring Boot 中 RabbitMQ 重复消费的原因及解决方案 #### 原因分析 RabbitMQ 的消息重复消费通常由以下几个原因引起: 1. **消费者异常退出未确认 ACK** 当消费者在处理消息期间发生崩溃或其他异常情况而未能向 RabbitMQ 返回 `basic.ack` 确认时,RabbitMQ 将重新投递该消息[^3]。 2. **网络波动或超时问题** 如果消费者的 ACK 请求在网络传输过程中丢失或者由于网络延迟超过了 RabbitMQ 设置的超时时间,则 RabbitMQ 可能会认为消息未被成功处理并再次投递[^1]。 3. **手动 ACK 实现不当** 在使用手动 ACK 模式下,如果程序逻辑设计不合理(例如多次调用 `channel.basicAck()`),可能会触发不必要的重复确认行为[^3]。 4. **并发竞争条件下的重复分发** 多个消费者实例之间可能存在短暂的时间窗口,在此期间某些特殊情况下可能导致同一消息被分配给不同消费者处理[^4]。 --- #### 解决方案 以下是针对以上提到的各种潜在原因所提供的具体应对措施: 1. **确保幂等性操作** - 对于业务层面的操作,应当保证其具备幂等特性。即无论执行多少次相同请求都只会产生唯一预期效果。可以通过引入唯一标识符来判断某条记录是否已经被处理过。例如利用数据库中的唯一约束字段作为依据[^1]。 2. **合理设置预取计数 Prefetch Count** - 控制每个信道允许同时接收但尚未完成确认的最大消息数量。通过降低 prefetc_count 参数可以减少因为单个消费者负载过高而导致的消息积压现象从而间接缓解重复消费风险[^3]。 ```java @Bean public ConnectionFactory connectionFactory() { CachingConnectionFactory factory = new CachingConnectionFactory(); factory.setHost("localhost"); factory.setPort(5672); factory.setUsername("guest"); factory.setPassword("guest"); // Set prefetch count to limit unacked messages per channel. factory.setPrefetchCount(1); return factory; } ``` 3. **启用事务支持或持久化存储中间状态** - 使用本地事务结合 RabbitMQ 提交机制以同步更新外部资源的状态变化;或者借助 Redis/Memcached 这类内存缓存服务保存临时进度信息以便后续恢复中断流程[^2]。 4. **优化错误处理策略** - 自定义异常处理器捕获所有可能出现的问题场景,并根据不同类型的故障采取相应的补救行动而不是简单粗暴地拒绝重入队列。比如对于瞬态错误可适当增加几次重试机会再决定放弃尝试。 ```java @ServiceActivator(inputChannel = "errorChannel") public void handleError(ErrorMessage errorMessage) { Throwable cause = errorMessage.getPayload(); if (cause instanceof AmqpRejectAndDontRequeueException) { log.error("Message rejected and not requeued", cause); } else { log.warn("Retrying failed message...", cause); retryTemplate.execute(context -> { processFailedMessage((Message<?>) errorMessage.getOriginalMessage().getHeaders().get(AmqpHeaders.DELIVERY_TAG)); return null; }); } } ``` 5. **调整心跳间隔 Heartbeat Interval 和 TCP Keepalive Options** - 调整客户端和服务端间的心跳频率参数有助于改善长时间无交互连接保持有效性的同时也减少了意外断开连接的概率[^2]。 --- ### 总结 综上所述,要有效防止 Spring Boot 应用中基于 RabbitMQ 架构下的消息重复消费状况的发生,需综合考虑应用层面上的设计改进和技术手段上的精细调控两方面因素共同作用才能达到理想的效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值