programing

Springboot @retryable 재시도 안 함

instargram 2023. 3. 23. 22:15
반응형

Springboot @retryable 재시도 안 함

다음 코드는 재시도되지 않습니다.제가 무엇을 빠뜨리고 있나요?

@EnableRetry
@SpringBootApplication
public class App implements CommandLineRunner
{
    .........
    .........


    @Retryable()
    ResponseEntity<String> authenticate(RestTemplate restTemplate, HttpEntity<MultiValueMap<String, String>> entity) throws Exception
    {
        System.out.println("try!");
        throw new Exception();
        //return restTemplate.exchange(auth_endpoint, HttpMethod.POST, entity, String.class);
    }

pom.xml에 다음과 같이 추가하였습니다.

    <dependency>
        <groupId>org.springframework.retry</groupId>
        <artifactId>spring-retry</artifactId>
        <version>1.1.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>

또한 @Retryable에 다른 인수 조합을 제공하려고 했습니다.

@Retryable(maxAttempts=10,value=Exception.class,backoff=@Backoff(delay = 2000,multiplier=2))

감사해요.

스프링 부트 2.0.2 릴리스에서는, 이 릴리스가@Retryable는, 같은 클래스에 재시도 가능한 메서드와 콜된 메서드가 있는 경우는 동작하지 않습니다.디버깅 시 포인트 컷이 올바르게 구축되지 않았습니다.현시점에서는, 이 문제의 회피책은, 다른 클래스에 메서드를 써, 콜 할 필요가 있습니다.

여기서 작업 예를 찾을 수 있습니다.

를 위해@Retryable발견될 방법에 대한 주석은 초기화된 컨텍스트에서 정확하게 호출되어야 한다.이 메서드는 스프링 컨텍스트에서 빈에서 호출됩니까, 아니면 다른 방법으로 호출됩니까?

테스트의 경우, 이것은 Runner가 사용하고 있는SpringJunit4ClassRunner?

Spring의 @Retryable, @Cacheable, @Transaction 등은 모두 Aspect Oriented Programming을 사용하여 구현됩니다.스프링은 프록시 기반 위빙을 통해 AOP를 구현합니다.프록시는 어떤 빈에서 다른 빈으로의 콜을 대행 수신합니다.프록시는 오브젝트 메서드에서 다른 오브젝트 메서드로의 콜을 대행 수신할 수 없습니다.이것은 프록시 기반의 직조에는 일반적으로 제한이 있습니다.

다음 솔루션은 이 제한에 대처합니다.1 ) 상기와 같이 @Autowired(또는 @Resource)를 사용하여 자기 참조가 있는 빈을 주입합니다.이 참조에 대한 콜은 프록시를 전송합니다.2) Spring 기본 프록시 기반 위빙 대신 AspectJ의 ClassLoader를 사용합니다.3) 위와 같이 각각의 콩에 방법들을 담는다.여러 가지 상황에서 해 봤는데 각각 장단점이 있어요.

내가 풀었어.재시도하는 메서드에서 무언가를 반환하면 @Retryable()이 작동하지 않는다는 것을 알게 되었습니다.

pom.xml의 maven 의존성

    <dependency>
        <groupId>org.springframework.retry</groupId>
        <artifactId>spring-retry</artifactId>
        <version>1.1.5.RELEASE</version>
    </dependency>

스프링 부트 어플리케이션자바

@SpringBootApplication
@EnableTransactionManagement
@EnableRetry
public class Application {

     public static void main(String[] args) throws Exception {
       SpringApplication.run(Application.class, args);
     }

}

incontroller.disclos에 있습니다.

@RestController
public class JavaAllDataTypeController {

@Autowired
JavaAllDataTypeService JavaAllDataTypeService;


@RequestMapping(
        value = "/springReTryTest",
        method = RequestMethod.GET
)
public ResponseEntity<String> springReTryTest() {

    System.out.println("springReTryTest controller");

    try {
         JavaAllDataTypeService.springReTryTest();
    } catch (Exception e) {
        e.printStackTrace();
    }

    return new  ResponseEntity<String>("abcd", HttpStatus.OK);
  }

}

현역의자바

@Service
@Transactional
public class JavaAllDataTypeService {

 // try the method 9 times with 2 seconds delay.
 @Retryable(maxAttempts=9,value=Exception.class,backoff=@Backoff(delay = 2000))
 public void springReTryTest() throws Exception {

    System.out.println("try!");
    throw new Exception();
  }

}

output: 9번 시도하고 예외를 발생시킵니다.

여기에 이미지 설명 입력

나는 원래 질문에서 설명한 것과 정확히 같은 문제를 가지고 있었다.

내 경우엔, 알고보니spring-boot-starter-aop종속성이 우연히 포함되지 않았습니다.내꺼에 추가한 후pom.xml,나의@Retryable방법은 예상대로 동작했습니다.

값 반환원@Retryable방법이 잘 통합니다.

반품 타입에도 대응합니다.

@Service
public class RetryService {

private int count = 0;

// try the method 9 times with 2 seconds delay.
@Retryable(maxAttempts = 9, value = Exception.class, backoff = @Backoff(delay = 2000))
public String springReTryTest() throws Exception {
    count++;
    System.out.println("try!");

    if (count < 4)
        throw new Exception();
    else
        return "bla";
  }

}

하고 분@Retryable같은 반에 있는 블록은 이렇게 할 수 있습니다.

여기서 중요한 것은 직접 자기주입 콩을 통해 메서드를 호출하지 않는 것입니다.

@Slf4j
@Service
public class RetryService {

    @Resource(name = "retryService")
    private RetryService self;

    public String getValue(String appender) {
        return self.getData(appender);
    }

    @Retryable(value = NumberFormatException.class, maxAttempts = 4, backoff = @Backoff(500))
    public String getData(String appender) {
        log.info("Calling getData");
        Integer value = Integer.parseInt(appender);
        value++;
        return value.toString();
    }

    @Recover
    public String recoverData(String appender) {
        log.info("Calling recoverData");
        return "DEFAULT";
    }

}

재시도 사용에 대한 자세한 내용은 여기를 참조하십시오.

RetryTemplate

@Bean
    public RetryTemplate retryTemplate() {
        RetryTemplate retryTemplate = new RetryTemplate();

        FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();
        fixedBackOffPolicy.setBackOffPeriod(2000l);
        retryTemplate.setBackOffPolicy(fixedBackOffPolicy);

        SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
        retryPolicy.setMaxAttempts(2);
        retryTemplate.setRetryPolicy(retryPolicy);

        return retryTemplate;
    }

그리고.

retryTemplate.execute(new RetryCallback<Void, RuntimeException>() {
    @Override
    public Void doWithRetry(RetryContext arg0) {
        myService.templateRetryService();
        ...
    }
});

나를 위해 운동했다.

원천

꽤 오래된 스레드지만 메서드의 가시성을 변경한 후 공유하려고 합니다.private로로 합니다.public,Retryable정상적으로 재시도하고 있습니다.

이는 위에서 언급한 셀프 리소스를 사용하는 것 외에 추가로 적용됩니다.

저도 같은 문제에 직면했지만, 나중에 조사와 조사를 통해 위의 @Retryable 주석과 함께 클래스 위에 @EnableRetry를 제공해야 한다는 것을 알게 되었습니다.이 @EnableRetry 주석은 사용자가 재시도하는 메서드를 지정한 클래스 위 또는 메인스프링 부트응용 프로그램클래스 위 중 하나로 할 수 있습니다.예를 들어 다음과 같습니다.

@RequiredArgsConstructor
**@EnableRetry**
@Service
public class SomeService {

  **@Retryable(value = { HttpServerErrorException.class, BadRequestException.class},
      maxAttempts = maxRetry, backoff = @Backoff(random = true, delay = 1000,
                         maxDelay = 8000, multiplier = 2))**
  public <T> T get( ) throws  HttpServerErrorException, BadRequestException {
    
     //write code here which you want to retry
  }

}

이것이 당신의 문제를 해결하는 데 도움이 되기를 바랍니다.

@Retryable재시도하고 싶은 메서드 바로 앞에 있습니다.

여기서부터:

public class MyClass {

  public String toBeRetried() {
    return delegateTo();
  }

  @Retryable
  public String delegateTo() {
    throw new Exception();
  }
}

이를 위해:

public class MyClass {

  @Retryable
  public String toBeRetried() {
    throw new Exception();
  }
}

언급URL : https://stackoverflow.com/questions/38212471/springboot-retryable-not-retrying

반응형