Невозможно поймать выброшенное исключение из асинхронного метода в Spring - PullRequest
0 голосов
/ 28 сентября 2019

Я не могу отловить сгенерированные исключения из асинхронного метода в Spring.Я написал необработанный обработчик исключений для перехвата, но безуспешно.Приложение позволит запустить любое количество постоянно выполняемых асинхронных заданий.Я думаю, что мой асинхронный метод должен вернуть Future, чтобы я мог сохранить его в hashmap и проверить его состояние или остановить работу.Я также могу получить все текущие задания, сохранив их.Я думаю, что я не могу использовать метод get из будущего, потому что если ввод правильный, он блокируется, и моя работа будет работать всегда.Мне нужно отправить статус как запущенный, если вход в порядке.Всякий раз, когда возникает исключение в методе Async, оно выбрасывается, но я не могу его перехватить.Как я могу это сделать?Вот мой полный код.

Application.java

@SpringBootApplication
@EnableAsync
public class Application  {

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

AsyncConfig.java

@EnableAsync
@Configuration
public class AsyncConfig implements AsyncConfigurer {

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(5);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("MyExecutor-");
        executor.initialize();
        return executor;
    }


    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new AsyncExceptionHandler();
    }
}

AsyncExceptionHandler.java

public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
    @Override
    public void handleUncaughtException(Throwable throwable, Method method, Object... obj) {

        System.out.println("Exception Cause - " + throwable.getMessage());
        System.out.println("Method name - " + method.getName());
        for (Object param : obj) {
            System.out.println("Parameter value - " + param);
        }
    }
}

createBucket.Java

@Service
public class createBucket {
    @Async
    public Future<String> start(String config){
        try {
            JSONObject map = new JSONObject(config);
            Jedis jedis = new Jedis(map.getString("jedisip"));
            jedis.auth(map.getString("password"));
            // code to make a kafka consumer subscribe to a topic given in config input
            while(true) {
                //forever running code which polls using a kafka consumer
            }
        }
        catch(JedisException j) {
            throw new JedisException("Some msg");
        }
    }
}

Endpoint.java

@Controller
public class Endpoint {
    @Autowired
    private createBucket service;

    private Future<String> out;
    private HashMap<String, Future<String>> maps = new HashMap<>();

    @PostMapping(value = "/start", consumes = "application/json", produces = "application/json")
    public ResponseEntity<String> starttask(@RequestBody String conf) {
        try {
        out = service.start(conf);
        maps.put(conf, out);
    }
    catch (Exception e) {
        return new ResponseEntity<>("exception", HttpStatus.BAD_REQUEST);
    }
        return new ResponseEntity<>("{\"started\":\"true\"}", HttpStatus.CREATED);
    }
}

1 Ответ

1 голос
/ 29 сентября 2019

Как указано в официальном документе, AsyncUncaughtExceptionHandler используется для void возвращаемого значения.https://docs.spring.io/spring/docs/5.1.10.RELEASE/spring-framework-reference/integration.html#spring-integration

В вашем сценарии я рекомендую использовать CompletableFuture и DeferredResult:

    @Async
    public CompletableFuture<String> start(String config) {
        CompletableFuture completableFuture = new CompletableFuture();
        try {
            JSONObject map = new JSONObject(config);
            Jedis jedis = new Jedis(map.getString("jedisip"));
            jedis.auth(map.getString("password"));
            completableFuture.complete("started!");
        }
        catch(JedisException j) {
            completableFuture.completeExceptionally(j);
        }

        return completableFuture;
    }
    @PostMapping(value = "/start", consumes = "application/json", produces = "application/json")
    public DeferredResult<ResponseEntity> starttask(@RequestBody String conf) {

        CompletableFuture<String> start = service.start(conf);

        DeferredResult<ResponseEntity> deferredResult = new DeferredResult<>();

        start.whenComplete((res, ex) -> {
            if (ex == null) {
                ResponseEntity<String> successEntity = new ResponseEntity<>("{\"started\":\"true\"}", HttpStatus.CREATED);\
                deferredResult.setResult(successEntity);
            } else {
                // handle ex here!
                ResponseEntity<String> exEntity = new ResponseEntity<>("exception", HttpStatus.BAD_REQUEST);
                deferredResult.setResult(exEntity);
            }
        });

        return deferredResult;

    }

Существует еще одна серьезная проблема.Следующий код не является потокобезопасным.

private Future<String> out;
private HashMap<String, Future<String>> maps = new HashMap<>();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...