Асинхронные задачи

Бин UiAsyncTasks позволяет выполнить операцию в отдельном потоке с использованием контекста безопасности текущего пользователя, а затем обновить экран с результатом этой операции.

Бин UiAsyncTasks использует под капотом CompletableFuture.

Если необходимо показать прогресс операции и дать пользователям возможность прервать её, используйте более мощный механизм фоновых задач.

Асинхронные задачи с результатом

Чтобы выполнить задачу, возвращающую результат, используйте билдер supplierConfigurer() и терминальный метод supplyAsync():

@Autowired
private UiAsyncTasks uiAsyncTasks;

private void loadCustomersAsync() {
    uiAsyncTasks.supplierConfigurer(this::loadCustomers) (1)
            .withResultHandler(customers -> {
                customersDc.setItems(customers); (2)
                notifications.create("Customers loaded").show();
            })
            .supplyAsync();
}

private List<Customer> loadCustomers() {
    return customerService.loadCustomers();
}
1 Supplier, переданный в метод supplierConfigurer(), будет выполнен с использованием контекста безопасности текущего пользователя.
2 Код, выполняемый внутри потребителя withResultHandler(), может безопасно обновлять компоненты экрана.

Асинхронные задачи без результата

Чтобы выполнить задачу, не возвращающую результат, используйте билдер runnableConfigurer() и терминальный метод runAsync():

private void synchronizeCustomersAsync() {
    uiAsyncTasks.runnableConfigurer(this::synchronizeCustomers)
            .withResultHandler(() -> {
                resultField.setValue("Synchronization completed");
            })
            .runAsync();
}

private void synchronizeCustomers() {
    customerService.synchronizeCustomers();
}

Обработка исключений

По умолчанию, если выполнение задачи завершится с исключением, оно будет записано в журнал приложения. Вы можете настроить это поведение, предоставив обработчик исключений:

private void loadCustomersAndHandleException() {
    uiAsyncTasks.supplierConfigurer(this::loadCustomers)
            .withResultHandler(customers -> {
                //...
            })
            .withExceptionHandler(ex -> {
                errorField.setValue(ex.getMessage());
            })
            .supplyAsync();
}

Обработка таймаутов

Используйте метод withTimeout(), чтобы задать значение таймаута выполнения. Если время ожидания превышено, будет выброшено исключение TimeoutException. Исключение TimeoutException можно обработать в методе withExceptionHandler().

private void loadCustomersWithTimeout() {
    uiAsyncTasks.supplierConfigurer(this::loadCustomers)
            .withResultHandler(customers -> {
                //...
            })
            .withTimeout(20, TimeUnit.SECONDS)
            .withExceptionHandler(ex -> {
                String errorText;
                if (ex instanceof TimeoutException) {
                    errorText = "Timeout exceeded";
                } else {
                    errorText = ex.getMessage();
                }
                errorField.setValue(errorText);
            })
            .supplyAsync();
}

Если явные значения таймаута не указаны, будет использоваться значение по умолчанию — 5 минут. Чтобы изменить это значение по умолчанию, используйте свойство приложения jmix.ui.async-task.default-timeout-sec.

Конфигурация ExecutorService

Бин UiAsyncTasks использует собственный ExecutorService для выполнения задач в отдельных потоках. Чтобы изменить размер пула по умолчанию для ExecutorService, используйте свойство приложения jmix.ui.async-task.executor-service.maximum-pool-size.