Asynchronous Tasks
The UiAsyncTasks
bean allows you to execute an operation in a separate thread using the security context of the current user, and then update the UI with the result of that operation.
The UiAsyncTasks
bean uses CompletableFuture
under the hood.
If you need to show the progress of an operation and give users the ability to abort it, use the more powerful Background Tasks mechanism.
Async Tasks With Result
To execute a task that returns a result, use the supplierConfigurer()
builder and the supplyAsync()
terminal method:
@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 passed into the supplierConfigurer() method will be executed with the security context of the current user. |
2 | Code executed inside the withResultHandler() consumer can safely update view components. |
Async Tasks Without Result
To execute a task that doesn’t return a result, use the runnableConfigurer()
builder and the runAsync()
terminal method:
private void synchronizeCustomersAsync() {
uiAsyncTasks.runnableConfigurer(this::synchronizeCustomers)
.withResultHandler(() -> {
resultField.setValue("Synchronization completed");
})
.runAsync();
}
private void synchronizeCustomers() {
customerService.synchronizeCustomers();
}
Exception Handling
By default, if the task execution fails with an exception, the exception is written to the application log. You can customize this behavior by providing an exception handler:
private void loadCustomersAndHandleException() {
uiAsyncTasks.supplierConfigurer(this::loadCustomers)
.withResultHandler(customers -> {
//...
})
.withExceptionHandler(ex -> {
errorField.setValue(ex.getMessage());
})
.supplyAsync();
}
Timeout Handling
Use the withTimeout()
method to set the execution timeout value. If the timeout is exceeded, the TimeoutException
will be thrown. The TimeoutException
can be processed in the withExceptionHandler()
method.
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();
}
If no explicit timeout values is specified, the default value of 5 minutes will be used. To change this default, use the jmix.ui.async-task.default-timeout-sec application property.
ExecutorService Configuration
The UiAsyncTasks
bean uses its own ExecutorService
to run tasks in separate threads. To modify the default pool size of the ExecutorService
, use the jmix.ui.async-task.executor-service.maximum-pool-size application property.