Server Push is not working

I have a simple MainView with MessageInput and MessageList. I wanted to show the user messages immediately on the view and then the assistant message once I get the response from AI service.

I have @Push on the Application class level.
But I am not able to make the User message appear immediately. What I am doing wrong?

@Route("")
public class MainView extends VerticalLayout {
    private final BedrockService bedrockService;
    private List<MessageListItem> messageListItemList = new ArrayList<>();

    public MainView(BedrockService bedrockService) {
        this.bedrockService = bedrockService;

        MessageList list = new MessageList();
        Instant instant = LocalDateTime.now()
                .toInstant(ZoneOffset.UTC);

        MessageInput input = new MessageInput();
        input.addSubmitListener(submitEvent -> {
            Thread.ofVirtual()
                    .start(UI.getCurrent()
                            .accessLater(() -> {
                                MessageListItem userMsg = new MessageListItem(submitEvent.getValue(),
                                        instant, "You");
                                messageListItemList.add(userMsg);
                                list.setItems(messageListItemList);
                            }, null));


            Thread.ofVirtual()
                    .start(UI.getCurrent()
                            .accessLater(() -> {
                                MessageListItem assistantMsg = new MessageListItem(bedrockService.callBedrockKB(submitEvent.getValue()),
                                        instant, "Assistant");
                                messageListItemList.add(assistantMsg);
                                list.setItems(messageListItemList);
                            }, null));
        });
        add(list, input);
    }
}

UI.getCurrent() uses a ThreadLocal. If you call it from the new thread you create, it won’t have a value. Store the current UI instance before you create the new thread.

Thanks @marcushellberg

I tried the below code change, still it’s not working!

MessageInput input = new MessageInput();
        input.addSubmitListener(submitEvent -> {
            MessageListItem userMsg = new MessageListItem(submitEvent.getValue(),
                    instant, "You");
            messageListItemList.add(userMsg);
            list.setItems(messageListItemList);

            var ui = UI.getCurrent();
            Thread.ofVirtual()
                    .start(ui
                            .accessLater(() -> {
                                MessageListItem assistantMsg = new MessageListItem(bedrockService.callBedrockKB(submitEvent.getValue()),
                                        instant, "Assistant");
                                messageListItemList.add(assistantMsg);
                                list.setItems(messageListItemList);
                            }, null));
        });

You need to run the slow part that has nothing to do with Vaadin outside of the access callback.

Consumer<String> accessor = UI.getCurrent().accessLater(message -> {
  Notification.show(message);
});

Thread.ofVirtual().start(() -> {
  String message = doSomethingSlow();
  accessor.accept(message);
});

Also note that you can add the user’s own message directly - no need to use a background thread and accessLater for that one. The background thread is only needed to allow the rest of the UI updates to proceed before the AI service has responded. And accessLater is only needed when updating the UI from that background thread after the AI service has responded.