Spring MVC how to get progress of running async task

19,256

Solution 1

Have you looked at the @Async annotation in the Spring reference doc?

First, create a bean for your asynchronous task:

@Service
public class AsyncServiceBean implements ServiceBean {

    private AtomicInteger cn;

    @Async
    public void doSomething() { 
        // triggers the async task, which updates the cn status accordingly
    }

    public Integer getCn() {
        return cn.get();
    }
}

Next, call it from the controller:

@Controller
public class YourController {

    private final ServiceBean bean;

    @Autowired
    YourController(ServiceBean bean) {
        this.bean = bean;
    }

    @RequestMapping(value = "/trigger")
    void triggerAsyncJob() {
        bean.doSomething();
    }

    @RequestMapping(value = "/status")
    @ResponseBody
    Map<String, Integer> fetchStatus() {
        return Collections.singletonMap("cn", bean.getCn());
    }        
}

Remember to configure an executor accordingly, e.g.

<task:annotation-driven executor="myExecutor"/>
<task:executor id="myExecutor" pool-size="5"/>

Solution 2

One solution could be: in your async thread, write to a DB, and have your checking code check the DB table for progress. You get the additional benefit of persisting performance data for later evaluation.

Also, just use the @Async annotation to kick off the asynchronous thread - makes life easier and is a Spring Way To Do It.

Solution 3

Check this github source, it gives pretty simple way of catching status of the background job using @Async of Spring mvc.

enter image description here https://github.com/frenos/spring-mvc-async-progress/tree/master/src/main/java/de/codepotion/examples/asyncExample

Share:
19,256
Josef Prochazka
Author by

Josef Prochazka

Updated on June 06, 2022

Comments

  • Josef Prochazka
    Josef Prochazka about 2 years

    I would like to start an asynchronous task from within controller like in following code sniplet from Spring docs.

    import org.springframework.core.task.TaskExecutor; 
    
    public class TaskExecutorExample { 
    
      private class MessagePrinterTask implements Runnable { 
    
        private int cn; 
    
        public MessagePrinterTask() { 
    
        } 
    
        public void run() { 
    //dummy code 
    for (int i = 0; i < 10; i++) { 
    cn = i; 
    } 
    } 
    
    } 
    
    private TaskExecutor taskExecutor; 
    
    public TaskExecutorExample(TaskExecutor taskExecutor) { 
        this.taskExecutor = taskExecutor; 
      } 
    
      public void printMessages() { 
    
          taskExecutor.execute(new MessagePrinterTask()); 
    
      } 
    } 
    

    afterwards in annother request (in the case that task is running) I need to check the progress of the task. Basicaly get the value of cn.

    What would be the best aproach in Spring MVC a how to avoid syncronisation issues.

    Thanks

    Pepa Procházka

  • Josef Prochazka
    Josef Prochazka about 12 years
    thaks, that was my first idea, but I need to only show the progres and I dont want to persist any information. Now I am logging the progress to tomcat log and I want to have faster way how to check it.
  • Javi Pedrera
    Javi Pedrera over 11 years
    hello, how do you get the taskExecutor? I have seen that is taken from the context using the .xml. Could you explain more your solution?
  • matsev
    matsev over 11 years
    Certainly, you can use @Autowired, @Inject, or any other Spring DI method that you would normally use.
  • matsev
    matsev over 11 years
    From the Spring Reference Docs: By default when specifying @Async on a method, the executor that will be used is the one supplied to the 'annotation-driven' element
  • Javi Pedrera
    Javi Pedrera over 11 years
    Thanks, I have implemented the example and I use a Loop in the function triggerAsyncJob but only one thread is fired. I need to execute at least 5 at the same time. I have to config anything else?
  • Fernando Fradegrada
    Fernando Fradegrada over 6 years
    It's a nice implementation, but it seems to me that this would only work for only one instance of the task going on. Is there any way to have multiple times the same task, for example "processFile" called by more than one user, and having the progress for each user?