Clarification on BackgroundTask done() Thread Handling (Jmix 2.4.3 with OAuth2)

Hi,

I’m a bit confused about how thread handling works for background tasks in Jmix (version 2.4.3).

I have a background task that can take a couple of seconds to complete. In its done() method, I navigate to a different view. My expectation (based on the documentation) is that done() should always be called on the UI thread. However, I’ve noticed that sometimes done() appears to be invoked on a background thread instead.

From my observations:

  • If the task finishes almost immediately, done() seems to run on the UI thread.
  • If the task takes a few seconds, done() seems to be executed on a background thread.

When done() runs on a background thread, RequestContextHolder.getRequestAttributes() returns null, and attempting to navigate causes Spring’s DefaultOAuth2AuthorizedClientManager to throw an error.

My questions are:

  • What determines which thread done() is invoked on?
  • Is there a recommended way to ensure that navigation and security context-dependent operations happen safely after a background task finishes? ( Right now I’m thinking of simply using Spring’s AuthorizedClientServiceOAuth2AuthorizedClientManager when getRequestAttributes are null. )

Thanks in advance for any clarification!

Hello!

The done() method is called from background task thread. However, the call to done() is wrapped inside UI.access() in order to to access the UI state, components and so on. That is why we can update user interface in this method (and name it UI thread). Since this is still background thread, we set actual authentication and store session attributes in ThreadLocalSessionData.

However, if you invoke getResult(), the background task becomes synchronous and done() method will be called from the UI thread where the task started.

I created an issue to update docs: Clarify from which thread the BackgroundTask done method called · Issue #1000 · jmix-framework/jmix-docs · GitHub

From my observations:

  • If the task finishes almost immediately, done() seems to run on the UI thread.
  • If the task takes a few seconds, done() seems to be executed on a background thread.

Could you share an example that reproduces the problem?

Hello!

Thanks a lot for the clarification. The weird thing is that it does seem to me, that done is not always on the background thread. I uploaded a simple project that reproduces the problem.
backgroundtask.zip (1.2 MB)
The project has two buttons, one starts a job that runs very fast, the other starts a slow task where I use Thread.sleep to simulate the slowness. Then I print out the thread name and the request attributes inside done() :

System.out.println("thread: " + Thread.currentThread().getName());
System.out.println("RequestContextHolder: " + RequestContextHolder.getRequestAttributes());

The fast task says its on http-nio-8080-exec-3 thread, which to me seems like the ui thread, and the slow task says BackgroundTask-1-admin.

Hello!

Thank you for the demo project! I reproduced this behavior, however we need to investigate it in more detail.

I created the issue: BackgroundTask sometimes invokes the done method in the UI thread from which the task was started · Issue #4395 · jmix-framework/jmix · GitHub

1 Like

Hi, @attila.h!

Could you please provide a sample code that is failed when invoking from the done() method? Currently, it’s unclear if the above behaviour is a bug or not (except that we still need to clarify it in the docs). The done() method does what it claims to do, i.e. give access the UI, using UI.access() which JavaDocs says:

Could you please provide a sample code that fails when invoked from the done() method? Currently, it is unclear whether the above behaviour is a bug or not (except for the fact that we still need to clarify this in the documentation). The done() method does what it says it does, i.e., gives access to the UI using UI.access(), which the JavaDoc says:

Please note that the command might be invoked on a different thread or later on the current thread…

Regards,
Gleb