0
votes

I have code like this. Each method is a stage exposed to rest call independently:

void methodA(@FormDataParam ("fd") fd){
//Executor spawns thread - takes around 15-30 min as per data
//main thread exits with "Process begun" message while thread spawned still running
}

void methodB(){
//Executor spawns thread - takes around 60-600 min as per data
//main thread exits with "Process begun" message while thread spawned still running
}

void methodC(){
//Executor spawns thread - takes around 10-60 min as per data
//main thread exits with "Process begun" message while thread spawned still running
}

These stages were executed sequentially earlier. Now, additional requirement is to execute them in one go if required. For that one single api has to be exposed as rest api like:

void methodAll(@FormDataParam ("fd") fd){
methodA(fd);
methodB();
methodC();
}

Problem is methodA(), methodB(), methodC() main thread return immediately while threads spawned by them are still running and hence result in start of execution of other subsequent methods before prior one completes.

I am in fix, how to solve this problem without substantial changes to existing three api?

1
One way -- use and pass in call backs - Hovercraft Full Of Eels
MetgodB needs result of methodA for make it's job? - Ruslan Stelmachenko
Best would be to refactor the code such that the three methods don't return void and don't do threading. Instead they simply perform their actions and return their results, then call the three in succession within a single background thread. - Hovercraft Full Of Eels
@HovercraftFullOfEels Thanks for looking into it. Yes, refactoring is one way as you suggested but I am keeping it as last option as it hinders with current execution pattern of independent run. If I dont get any better solution then I will go with it. - KRS
@djxak - no friend. MethodB doesnt need input from MethodA but since these are lifecycle stages methodA must complete before methodB. Actually, currently methodA writes its status in a DB table. methodB never starts if doesnt have status completed corresponding to methodA. Hence one way is to loop around with sleep of certain time over status but I am open to other better solutions. - KRS

1 Answers

2
votes

Now you have (pseudocode):

class RestController {

  void methodA() {
    new Thread() {
      // some hard work
    }.start();
  }

  void methodB() {
    new Thread() {
      // some hard work
    }.start();
  }

}

After refactoring:

class RestController {

  void methodA() {
    new Thread() {
      service.methodA();
    }.start();
  }

  void methodB() {
    new Thread() {
      service.methodB();
    }.start();
  }

  void methodD() {
    new Thread() {
      service.methodA();
      service.methodB();
    }.start();
  }

}

class Service {

  void methodA() {
    // some hard work
  }

  void methodB() {
    // some hard work
  }

}

Of course you can use ExecutorService or any other helpers for threading instead of manual thread spawning.

If your controller do validation, preprocess & postProcess before/after spawning thread, as you say, and it really the same code, then you can extract it into method which takes Runnable and executes it between pre- and postProcess to avoid duplication.

  void execute(Runnable runnable) {
    // do validation
    // do preProcess
    new Thread(runnable).start();
    // do postProcess
  }
...
  void methodA() {
    execute(new Runnable() {
      @Override
      void run() {
        service.methodA();
      }
    });
  }

Or you can just do this validation in your service methods.