重试机制@Retryable
<dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> </dependency>
import com.example.cesium.service.IRetryService; import lombok.extern.slf4j.Slf4j; import org.springframework.retry.annotation.Backoff; import org.springframework.retry.annotation.Retryable; import org.springframework.stereotype.Service; import java.time.LocalTime; @Service @Slf4j public class IRetryServiceImpl implements IRetryService { @Override @Retryable(value=Exception.class,maxAttempts = 3,backoff = @Backoff(value = 2000,multiplier = 1.5)) public int test(Integer code) throws Exception { log.info("testRetry时间:" + LocalTime.now()); if (code == 0) { throw new Exception("出现异常!"); } log.info("testRetry 成功调用!"); return 200; } }
value:抛出指定异常才会重试
include:除指定异常意外都重试
maxAttempts:最大重试次数。默认3次
backoff:重试等待策略,默认使用@Backoff , @Backoff的value默认为1000L,
mutiplier为指定延迟倍数
value = 2000,multiplier = 1.5 第一次重试2秒 , 第二次3秒, 第三次 4.5秒
场景: 交通规则触发时,需要下发指令,但网络可能会抖动等异常情况,会导致车辆无法及时控制车辆。
优化: 网络抖动时,多次请求重试,保证下发指令有效执行。
实现:
/** * 发送交通控制解除指令 * * @param traffic * @param cmd */ @Retryable(include = {RetryException.class}, maxAttempts = 3, backoff = @Backoff(delay = 1000L, multiplier = 2)) @Override @Async public Boolean sendOperationCommand(TrafficVehiclesVo traffic, int cmd) { //拼接前车指令参数 String code = traffic.getCode(); BogieTrafficVo command = new BogieTrafficVo(); command.setDeviceId(code); command.setOrder(cmd); command.setPointLongitude(traffic.getLongitude()); command.setPointLatitude(traffic.getLatitude()); command.setPointAltitude(traffic.getAltitude()); // 根据规则引擎返回 下发车端指令 进行交通控制 增加判断条件限制重复下发相同指令 log.info("车辆:{} 进行交通控制 {}", command.getDeviceId(), command); if (cmd == 1) { Double score = stringRedisTemplate.opsForZSet().score(DispatchRedisConstant.DISPATCH_CONTROL_URGENT, code); stringRedisTemplate.opsForSet().remove(DispatchRedisConstant.DISPATCH_CONTROL_FIXED, code); if (null != score && !Double.isNaN(score)) { log.error("-------------车辆:{} 已经紧急停车,交通控制无法执行放行指令", code, cmd); return false; } } else if (cmd == 3) {//定点停车缓存中增加车辆code stringRedisTemplate.opsForSet().add(DispatchRedisConstant.DISPATCH_CONTROL_FIXED, code); } R result = bogieIotDispathClient.bogieDispatchTraffic(command); //stringRedisTemplate.opsForHash().put(DispatchRedisConstant.DISPATCH_TRAFFIC_CONTROL, command.getDeviceId() + "-" + command.getOrder(), command.toString()); if (result.getCode() == 200 && command.getDeviceId().equals(code)) { return true; } throw new RetryException("run contrl fail"); } /** * 下发指令 * * @param traffic * @param cmd * @return */ @Retryable(include = {RetryException.class}, maxAttempts = 3, backoff = @Backoff(delay = 1000L, multiplier = 2)) @Override @Async public Boolean sendRelieveCommad(TrafficVehiclesVo traffic, int cmd) { log.info("before:{}", traffic); String code = traffic.getCode(); BogieTrafficVo freeCommand = new BogieTrafficVo(); freeCommand.setDeviceId(code); freeCommand.setOrder(cmd); if (cmd == 1) { Double score = stringRedisTemplate.opsForZSet().score(DispatchRedisConstant.DISPATCH_CONTROL_URGENT, code); stringRedisTemplate.opsForSet().remove(DispatchRedisConstant.DISPATCH_CONTROL_FIXED, code); if (null != score && !Double.isNaN(score)) { log.error("-------------车辆:{} 已经紧急停车,交通控制无法执行放行指令", code, freeCommand); return false; } } R result = bogieIotDispathClient.bogieDispatchTraffic(freeCommand);// 下发解除控制指令后移除redis中设置主车的下发指令缓存 //stringRedisTemplate.opsForHash().put(DispatchRedisConstant.DISPATCH_TRAFFIC_CONTROL, command.getDeviceId() + "-" + command.getOrder(), command.toString()); if (result.getCode() == 200 && freeCommand.getDeviceId().equals(code)) { log.info("车辆:{} 进行解除交通控制 {}", freeCommand.getDeviceId(), freeCommand); return true; } throw new RetryException("stop contrl fail"); } @Recover public void recover(RetryException e) { log.error("recovery,{}", e.getMessage()); }