How to run a Backgroundable Task in progress and synchronously?

Hello,

what I am trying to achieve:

Run multiple tasks in a background threads, but synchronously with order each after the other.

I have tried to search the forum for the answer, but still have an open question.
Assuming code like this:

          ApplicationManager.getApplication().invokeAndWait(new Runnable() {
            @Override
            public void run() {
              ProgressManager.getInstance().runProcessWithProgressSynchronously(
                  myRunnable, "Running my task", true, project
              );
            }
          }, ModalityState.NON_MODAL);
          // this line is executed after myRunnable is finished


Good about this I can cancel the running task, bad is, you cannot move it to background and the ui is blocked from doing any actions.

I tried to change this code to:

          ApplicationManager.getApplication().invokeAndWait(new Runnable() {
            @Override
            public void run() {
              BackgroundableWrapper backgroundableWrapper = new BackgroundableWrapper(project, "Running my task", myRunnable);
              ProgressManager.getInstance().run(backgroundableWrapper);
            }
          }, ModalityState.NON_MODAL);
          // this line is run in a non blocking way, without waiting for background task to complete. In my case it is bad.


// where BackgroundableWrapper is similar to RunnableBackgroundableWrapper:

public class BackgroundableWrapper extends Task.Backgroundable {   private final Runnable task;   public BackgroundableWrapper(@Nullable Project project, @NotNull String title, Runnable task) {     super(project, title, true, PerformInBackgroundOption.DEAF);     this.task = task;   }   public void run(@NotNull ProgressIndicator indicator) {     task.run();   } }


Good now is the task is cancable and backgroundable, bad is it is running async without waiting.


How can I do a cancable backgroundable task running in a "runProcessWithProgressSynchronously" mode?

Thank you!

5 comments
Comment actions Permalink

By definition, background tasks can't be run synchronously (because otherwise, the event dispatch thread would be locked waiting for the background task to complete, the user would not be able to perform any other actions, and the "background" operation would not run in background at all). What you need to do is, when your background operation completes, use invokeLater() to transfer the control back to the event dispatch thread to start the next step of the operation.

0
Comment actions Permalink

My problem is what supposed to be happen in Application.getApplication().invokeLater(new Runnable() {... }) after task is done is not under my control. To be more precise,
I run inside GlobalInspectionContextExtension#performPreRunActivities a long running task
After performPreRunActivities is done IDEA executes the inspections.
Now because all tasks are backgroundable, performPreRunActivities is done before they are finished, then inspections are executed, but do nothing, because they need the results from the tasks.
I need to tell the inspections context to execute first if tasks are done.
If transforming this issue to .NET I need something like

Results results =await myTask;



If you like to see the full source code: https://github.com/sonar-intellij-plugin/sonar-intellij-plugin/blob/master/src/main/java/org/intellij/sonar/analysis/SonarQubeInspectionContext.java

0
Comment actions Permalink

The performPreRunActivities() method is already called under a progress indicator; you can't (and shouldn't) create any additional progress indicators inside your own code.

0
Comment actions Permalink

ok, following your instructions:

public class MyInspectionContext implements GlobalInspectionContextExtension<MyQubeInspectionContext> {

   @Override
   public void performPreRunActivities(...) {


          final ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator();

          ...
         
          ProgressManager.getInstance().runProcessWithProgressAsynchronously(new BackgroundableWrapper(project, "Task 1", task1), progressIndicator);
         
          ProgressManager.getInstance().runProcessWithProgressAsynchronously(new BackgroundableWrapper(project, "Task 2", task2), progressIndicator);
          ...
}

public class MyGlobalInspectionTool extends GlobalSimpleInspectionTool {

     @Override
      public void checkFile(...) {
          // this is executed before task 1 and task 2 are done
      }


}
0
Comment actions Permalink

update:


now it works, it is simpler as I don't need to care about tasks at all.

@Override
   public void performPreRunActivities(...) {
         
          task1.run();
         
          task2.run();
          ...
}


IntelliJ is already wrapping it into a backgroundable task :-)

0

Please sign in to leave a comment.