Search code examples
javaasynchronousvaadinvaadin-flow

UI#access never executes task


I am trying to save user settings asynchronously when user change some of them and show notification once they are saved. I want the settings to be saved once per 2 seconds at maximum, not every time user change them. For this task I am using ScheduledExecutorService. However the notification is not shown even when I try show it in UI#access method. Vaadin Server Push Configuration.

// on setting changed
if (saveSettingsTask != null) {
    if (saveSettingsTask.state() == Future.State.RUNNING) {
        return;
    }
    saveSettingsTask.cancel(false);
}
saveSettingsTask = SCHEDULED_EXECUTOR_SERVICE.schedule(() -> {
    saveSettings(); // settings are saved
    UI.getCurrent().access(() -> {
        NotifUtils.success("test", Notification.Position.BOTTOM_CENTER); // never reach this
    });
    NotifUtils.success("test", Notification.Position.BOTTOM_CENTER); // i also tried to show it here, but it does not work
    UI.getCurrent().push(); // even tried to call push manually altough i have @Push annotation on my AppShellConfigurator class
    return null;
}, 2, TimeUnit.SECONDS);

To start the app I am using main method in my IDE:

@SpringBootApplication
@Theme(value = "myapp")
@PWA(name = "myapp", shortName = "myapp")
@Push
public class Application extends SpringBootServletInitializer implements AppShellConfigurator {
    
    // dev only
    public static void main(final String[] args) throws Exception {
        new SpringApplicationBuilder(Application.class)
                .listeners(new DatabasePropertiesSetup())
                .run(args);
    }
    
    @Override
    protected SpringApplicationBuilder configure(final SpringApplicationBuilder application) {
        return application.listeners(new DatabasePropertiesSetup())
                .sources(Application.class);
    }
}

I also tried to add @EnableVaadin annotation with package in which the Application is, as someone suggested in Server Push Vaadin documentation in comments, however this did not help.

I am using Vaadin 24.3.7 and spring boot 3.2.2, java 21


Solution

  • You have to capture the current UI when you start the background task (while inside a UI session). Once your scheduled task runs, the UI is not there anymore. UI::getCurrent relies on a thread-local, that gets filled when a request enters the server.

    Also try/catch in your runner and make sure you notice the error (e.g. use proper logging). Otherwise errors might eaten up to the point where the whole scheduler dies.