前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >淘宝上传图片api报了“HSF thread pool is full”,很烦但问题还要解!幸亏有这个组件轻松搞定

淘宝上传图片api报了“HSF thread pool is full”,很烦但问题还要解!幸亏有这个组件轻松搞定

作者头像
烟雨平生
发布2024-12-20 14:41:10
发布2024-12-20 14:41:10
7600
代码可运行
举报
文章被收录于专栏:数字化之路数字化之路
运行总次数:0
代码可运行

又又又报错了:

发现淘宝和微信都是一个德行,对客端的页面和交互对用户各种谄媚,各种小惊喜,各种体验优化,各种暖心交互,各种闭环;对商端做的真是一坨屎,没有提供场景化完成一个功能的文档,满眼都是鸡零狗碎的东一个西一个的API,文档页面看着老旧丑陋没有技术含量,并且不好找,找个功能需要找半天,没有闭环想用个功能需要各种申请,烦死个人。权限开通后,一个不小心权限就被封功能不能用,又是各种申诉各种整改,憋屈。气死个人。

吐槽又不能解决问题。先来看看这个报错吧。好在淘宝还可以提工单,这点比微信更有助于解决遇到的问题。

淘宝说我就是这样,也不怕你重试,你再来多请求几次呀!!

既然淘宝方案给了,那就增加重试吧。

自己写一个for循环+sleep来完成重试有些slow+花时间,感觉还是用现成的组件进行重试更优雅。

之前做过技术选型,选了Spring Retry。Spring Retry就不在这展开介绍了,详见文末。

要在Spring框架中基于Spring-Retry实现接口抛异常后的Retryable功能,可以遵循以下步骤:

添加依赖

首先,你需要在你的Spring Boot项目的pom.xml文件中添加spring-retry的依赖。

代码语言:javascript
代码运行次数:0
复制
<!-- 重试相关依赖包 -->
<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
    <version>1.3.4</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.4</version>
</dependency>

开启重试功能

默认是不开启的。

在你的Spring Boot应用的主启动类上添加@EnableRetry注解,以开启重试机制的支持。

代码语言:javascript
代码运行次数:0
复制
@SpringBootApplication
@EnableRetry
public class RetryApplication {
    public static void main(String[] args) {
        SpringApplication.run(RetryApplication.class, args);
    }
}

声明式配置重试策略

使用@Retryable注解:

在需要实现重试的方法上添加@Retryable注解,这样当方法抛出指定异常时,就会自动进行重试。

代码语言:javascript
代码运行次数:0
复制
import lombok.extern.slf4j.Slf4j;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
import java.util.concurrent.ThreadLocalRandom;

@Service
@Slf4j
public class RetryServiceImpl implements RetryService {    

@Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 1000, multiplier = 1.5))    
@Override    
public String doBiz() {        
int countVal = ThreadLocalRandom.current().nextInt(10);        
if (countVal > 1) {            
// 这里可以使自定义异常,@Retryable中value需与其一致            
log.warn("doBiz 执行业务代码失败 countVal {} ", countVal); 
           throw new RuntimeException("执行业务代码失败");        
           }        
           log.info("doBiz 执行业务代码成功 countVal {} ", countVal);        
           return "success";    
        }    
    }



}

翻译一下:

在上面的例子中,@Retryable注解的参数含义如下:

  • value:指定重试的异常类型,这里是Exception,表示当抛出Exception类型异常时会触发重试。
  • maxAttempts:最大重试次数,这里是3次(包括第一次尝试)。
  • backoff:重试的间隔策略,delay指定了第一次重试的延迟时间(1000毫秒),multiplier指定了延迟时间的增长倍数(1.5倍)。

可视化调试过程

启用详细的日志记录:

在Spring的配置中启用DEBUG级别的日志,这样可以查看Spring Retry的内部工作情况,包括代理创建和重试逻辑。可视化的看到重试的过程

代码语言:javascript
代码运行次数:0
复制
# 在application.properties或application.yml中添加
logging.level.org.springframework.retry=DEBUG

光说不练假把式

写个测试用例,Run起来

代码语言:javascript
代码运行次数:0
复制
import com.tangcheng.toolbox.ToolBoxApplication;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;


@SpringBootTest(classes = ToolBoxApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Slf4j
class RetryServiceImplTest {   
 
    @Autowired    
    private RetryService retryService;  
  
    @Test    
    void doBiz() {
        String result = retryService.doBiz();
        log.info("result {} ", result);   
    }      
}

执行结果:

代码语言:javascript
代码运行次数:0
复制
2024-12-10 21:21:24.749  INFO 22518 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 65177 (http) with context path ''
2024-12-10 21:21:24.760  INFO 22518 --- [           main] c.t.t.b.tool.RetryServiceImplTest        : Started RetryServiceImplTest in 2.932 seconds (JVM running for 4.005)
2024-12-10 21:21:24.991 DEBUG 22518 --- [           main] o.s.retry.support.RetryTemplate          : Retry: count=0
2024-12-10 21:21:24.999  WARN 22518 --- [           main] c.t.t.business.tool.RetryServiceImpl     : doBiz 执行业务代码失败 countVal 7 
2024-12-10 21:21:24.999 DEBUG 22518 --- [           main] o.s.r.backoff.ExponentialBackOffPolicy   : Sleeping for 1000
2024-12-10 21:21:26.004 DEBUG 22518 --- [           main] o.s.retry.support.RetryTemplate          : Checking for rethrow: count=1
2024-12-10 21:21:26.004 DEBUG 22518 --- [           main] o.s.retry.support.RetryTemplate          : Retry: count=1
2024-12-10 21:21:26.004  INFO 22518 --- [           main] c.t.t.business.tool.RetryServiceImpl     : doBiz 执行业务代码成功 countVal 0 
2024-12-10 21:21:26.004  INFO 22518 --- [           main] c.t.t.b.tool.RetryServiceImplTest        : result success 

第二次重试时成功了

可以看到,Spring Retry的debug日志与业务代码中打印日志是一致的。

正常情况下,生产环境是不会开debug日志的,想在重试失败时进行一些操作,譬如打印特殊的日志,譬如发一条告警通知,需要怎么做?在加了@Retryable注解的方法中直接加,肯定是不行的。至于原因,各位大佬想一下为什么

实际上,这种场景Spring Retry也是支持的。你可以使用@Recover注解来指定一个方法,当重试次数耗尽后,这个方法将被调用以进行异常恢复处理。

@Recover来兜底

@Recover注解用于标记一个方法,该方法会在@Retryable注解标记的方法重试后仍然失败时被调用。这个方法可以作为最后的防线,处理重试失败后的情况,比如记录日志、发送告警、或者返回一个默认值等。

代码语言:javascript
代码运行次数:0
复制
@Recover
public String doBizRecover(Exception e) {    
    log.warn("@Recover回调方法执行 重试后仍然没有成功");    
    return "报错了 " + e.getMessage();
}

多跑几次测试用例,尝试触发重试后仍然失败的场景:

代码语言:javascript
代码运行次数:0
复制
2024-12-10 21:31:08.452  INFO 24877 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 50004 (http) with context path ''
2024-12-10 21:31:08.462  INFO 24877 --- [           main] c.t.t.b.tool.RetryServiceImplTest        : Started RetryServiceImplTest in 2.785 seconds (JVM running for 3.909)
2024-12-10 21:31:08.690 DEBUG 24877 --- [           main] o.s.retry.support.RetryTemplate          : Retry: count=0
2024-12-10 21:31:08.696  WARN 24877 --- [           main] c.t.t.business.tool.RetryServiceImpl     : doBiz 执行业务代码失败 countVal 3 
2024-12-10 21:31:08.697 DEBUG 24877 --- [           main] o.s.r.backoff.ExponentialBackOffPolicy   : Sleeping for 1000
2024-12-10 21:31:09.701 DEBUG 24877 --- [           main] o.s.retry.support.RetryTemplate          : Checking for rethrow: count=1
2024-12-10 21:31:09.701 DEBUG 24877 --- [           main] o.s.retry.support.RetryTemplate          : Retry: count=1
2024-12-10 21:31:09.702  WARN 24877 --- [           main] c.t.t.business.tool.RetryServiceImpl     : doBiz 执行业务代码失败 countVal 2 
2024-12-10 21:31:09.702 DEBUG 24877 --- [           main] o.s.r.backoff.ExponentialBackOffPolicy   : Sleeping for 1500
2024-12-10 21:31:11.207 DEBUG 24877 --- [           main] o.s.retry.support.RetryTemplate          : Checking for rethrow: count=2
2024-12-10 21:31:11.207 DEBUG 24877 --- [           main] o.s.retry.support.RetryTemplate          : Retry: count=2
2024-12-10 21:31:11.208  WARN 24877 --- [           main] c.t.t.business.tool.RetryServiceImpl     : doBiz 执行业务代码失败 countVal 4 
2024-12-10 21:31:11.208 DEBUG 24877 --- [           main] o.s.retry.support.RetryTemplate          : Checking for rethrow: count=3
2024-12-10 21:31:11.208 DEBUG 24877 --- [           main] o.s.retry.support.RetryTemplate          : Retry failed last attempt: count=3
2024-12-10 21:31:11.209  WARN 24877 --- [           main] c.t.t.business.tool.RetryServiceImpl     : @Recover回调方法执行 重试后仍然没有成功
2024-12-10 21:31:11.209  INFO 24877 --- [           main] c.t.t.b.tool.RetryServiceImplTest        : result 报错了 执行业务代码失败 

Spring Retry的优点

Spring Retry 提供了一系列优点,使其成为处理暂时性故障和提高应用程序弹性的有力工具:

  1. 简化编码
    • 开发者无需手动编写重试逻辑,Spring Retry 通过注解和模板方法提供了重试的实现,大大简化了代码。
  2. 一致的API
    • 提供了一致的API来处理重试,无论是注解方式还是编程式方式,都遵循相同的设计原则。
  3. 灵活的重试策略
    • 支持自定义重试策略,包括重试次数、重试间隔(包括固定间隔和指数退避策略)以及重试条件。
  4. 异常处理
    • 允许开发者指定哪些异常应该触发重试,以及定义重试失败后的恢复逻辑。
  5. 集成AOP
    • 利用Spring AOP(面向切面编程),Spring Retry 可以在不修改业务逻辑代码的情况下,为方法添加重试功能。
  6. 状态管理
    • 支持有状态的重试,这意味着在重试过程中可以保留异常信息和重试状态。
  7. 兼容性
    • 与Spring生态系统中的其他组件(如Spring Data、Spring Integration)良好集成。
  8. 透明性
    • 对于调用者来说,重试是透明的,不需要关心重试的具体实现。
  9. 回退策略
    • 提供了在重试失败后执行的回退策略,允许开发者定义失败后的处理逻辑。
  10. 监听器支持
    • 通过实现RetryListener接口,可以在重试的不同阶段插入自定义逻辑,如记录日志、更新状态等。
  11. 可配置性
    • 允许在全局和方法级别配置重试参数,使得重试策略可以根据不同的业务需求进行调整。
  12. 提高可靠性
    • 对于可能由于网络问题或服务瞬时不可用而导致失败的操作,重试机制可以显著提高应用程序的可靠性。
  13. 减少人工干预
    • 自动化的重试减少了对人工干预的依赖,特别是在处理大量事务时。
  14. 易于测试
    • 由于重试逻辑被封装在Spring Retry中,可以更容易地编写单元测试和集成测试。

REFERENCE

阿里P7大佬首次分享Spring Retry不为人知的技巧https://zhuanlan.zhihu.com/p/37625630

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-12-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 的数字化之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 添加依赖
  • 开启重试功能
  • 声明式配置重试策略
  • 可视化调试过程
  • 光说不练假把式
  • @Recover来兜底
  • Spring Retry的优点
  • REFERENCE
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档