Spring-Boot: scalability of a component

Viewed 106

I am trying Spring Boot and think about scalabilty.

Lets say I have a component that does a job (e.g. checking for new mails). It is done by a scheduled method.

e.g.

@Component
public class MailMan
{
  @Scheduled (fixedRateString = "5000")
  private void run () throws Exception
  { //... }
}

Now the application gets a new customer. So the job has to be done twice.

How can I scale this component to exist or run twice?

3 Answers

Interesting question but why Multiple components per customer? Can scheduler not pull the data for every customer on scheduled run and process the record for each customer? You component scaling should not be decided based on the entities evolved in your application but the resources utilization by the component. You can have dedicated components type for processing the messages for queues and same for REST. Scale them based on how much each of them is getting utilized.

Instead of using annotations to schedule a task, you could do the same thing programmatically by using a ScheduledTaskRegistrar. You can register the same bean multiple time, even if it is a singleton.

public class SomeSchedulingConfigurer implements SchedulingConfigurer {

  private final SomeJob someJob; <-- a bean that is Runnable

  public SomeSchedulingConfigurer(SomeJob someJob) {
    this.someJob = someJob;
  }
  
  @Override
  public void configureTasks(@NonNull ScheduledTaskRegistrar taskRegistrar) {
    int concurrency = 2;
    IntStream.range(0, concurrency)).forEach(
      __ -> taskRegistrar.addFixedDelayTask(someJob, 5000));
  }

}

Make sure the thread executor you are using is large enough to process the amount of jobs concurrently. The default executor has exactly one thead :-). Be aware that this approach has scaling limits.

I also recommend to add a delay or skew between jobs, so that not all jobs run at exactly the same moment.

See SchedulingConfigurer and ScheduledTaskRegistrar for reference.

The job needs to run only once even with multiple customers. The component itself doesn't need to scale at all. It just a mechanism to "signal" that some logic needs to be run at some moment in time. I would keep the component really thin and just call the desired business logic that handles all the rest e.g.

@Component
public class MailMan {

  @Autowired
  private NewMailCollector newMailCollector;

  @Scheduled (fixedRateString = "5000")
  private void run () throws Exception { 
      // Collects emails for customers
      newMailCollector.collect();
  }
}

If you want to check for new e-mails per customer you might want to avoid using scheduled tasks in a backend service as it will make the implementation very inflexible.

Better make an endpoint available for clients to call to trigger that logic.

Related