Retryable не работает в отдельном потоке

Я пытаюсь проверить, повторялся ли мой вызов метода несколько раз, если возникло какое-то исключение. И если я вызываю метод напрямую, он работает нормально. Но если я вызову его в отдельном потоке, мой тестовый метод завершится ошибкой, он не увидит никаких повторных попыток. Это мои методы:

public class MyClass {
        @Inject
        private ServiceClass service;

        @Retryable(value = {Exception.class}, maxAttempts = 5, backoff = @Backoff(delay = 30000))
        public void retryMethod(Integer id, double dId)
        {
            Thread remoteDIUpdater = new Thread(() -> {
            service.updateIndex(id, dId);
            }
            );
        remoteDIUpdater.setDaemon(true);
        remoteDIUpdater.setName("RemoteDIUpdaterThread");
        remoteDIUpdater.start();
        }

        @Recover
        public void recover(Exception ex, Integer id, double dId)
        {
            logger.error("Error", ex);
        }
}

И это мой тестовый класс:

public class TestClass
{
    @Inject
    @InjectMocks
    private MyClass myClass;

    @Mock     
    private private ServiceClass service;

    @Test
    public void testMethod()
    {
        Integer id = 1;
        double dId = 2d;
        doThrow(Exception.class).when(service).retryMethod(id, dId);
        myClass.updateBetDangerIndex(betId, dangerIndex);
        verify(service, Mockito.times(5)).retryMethod(null, id, iId);
    }

}

Возможно, мой метод тестирования неверен. НО, если я вызову свой метод просто так (без потока):

@Retryable(value = {Exception.class}, maxAttempts = 5, backoff = @Backoff(delay = 30000))
            public void retryMethod(Integer id, double dId)
            {             
                service.updateIndex(id, dId);              
            }

, мой тестовый метод работает нормально. В чем ошибка?


person Sviatlana    schedule 16.10.2017    source источник
comment
Ваш тест неверен. Вы издеваетесь над вещами и сами создаете новый экземпляр (в основном @Inject бесполезен), и поэтому @Retry ничего не сделает.   -  person M. Deinum    schedule 16.10.2017
comment
Я использую контекст тестовой пружины, и инъекция работает хорошо. Мой тест хорошо работает с многопоточностью.   -  person Sviatlana    schedule 16.10.2017
comment
Нет, это не так... @InjectMocks делает @Inject бесполезным, поскольку он создаст новый экземпляр и внедрит в него издевательские зависимости. Он не будет использовать экземпляр, введенный Spring. Следовательно, ваш тест просто неверен.   -  person M. Deinum    schedule 16.10.2017
comment
Я упростил свой код и, возможно, сделал ошибку или не упомянул что-то. Проблема не в @|nject или чем-то подобном. Не знаю, как протестировать такое многопоточное приложение.   -  person Sviatlana    schedule 16.10.2017
comment
Да, это проблема... @Retry работает с АОП, который применяется через Spring. Поскольку вы используете @ InjectMocks, вы получаете новый экземпляр без прокси. В основном вы получаете new MyClass() здесь без применения АОП. Итак, ваш тест снова неверен.   -  person M. Deinum    schedule 16.10.2017
comment
Почему он хорошо работает без потоков?   -  person Sviatlana    schedule 16.10.2017
comment
Проблема с потоками в том, что они не ждут, а выполняются в фоновом режиме. В основном у вас будет такая же проблема в вашем живом производственном коде. Вместо этого вы должны использовать @Async и реализовать другой способ выполнения повторных попыток.   -  person M. Deinum    schedule 16.10.2017


Ответы (1)


Вероятно, вам нужно добавить Thread.join() после remoteDIUpdater.start(), чтобы предотвратить завершение основного потока до вашего потока.

person niemar    schedule 16.10.2017
comment
с этим методом вызывается только один раз. - person Sviatlana; 16.10.2017
comment
Почему вы предполагаете, что retryMethod будет вызываться 5 раз? maxAttempts = 5, но это не значит, что retryMethod будет вызываться 5 раз - person niemar; 16.10.2017
comment
doThrow(Exception.class).when(service).retryMethod(id, dId); - из-за этого. - person Sviatlana; 16.10.2017