Implementing worker processes in a Spring Boot application

Issue

Intro

I am currently running a Spring-Boot application through Heroku on a single web dyno. Due to the large number of intensive background tasks (fetching resources from 3rd party APIs, sending mails, etc.), I would like to move all these "heavy jobs" on a second worker dyno/process. However, I am facing several difficulties in properly exposing the application components (e.g. @Repositories) to the second worker process.

What I have attempted so far

I’ve created a second main class (BackgroundWorker) which I specify in the Procfile as a worker process. The following class is then called in order to initialize the background tasks.

@Service
@EnableMongoRepositories("com.a.viz.db")
@ComponentScan("com.a.viz.db")
@EntityScan("com.a.viz.model")
public class TaskHandler {
    @Autowired
    UProductRepository productRepository;

    public void initScheduler()
    {
        Runnable fetchProducts = () -> {
            Scheduler.fetchProducts(productRepository);
        };
    }
}

While the main class looks like this:

public class BackgroundWorker {
    static Logger logger =  LoggerFactory.getLogger(BackgroundWorker.class);

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.scan("com.a.viz.workers");
        context.refresh();
        TaskHandler handler = context.getBean(TaskHandler.class);
        handler.initScheduler();
    }
}

Upon running the above snippet, I get an unsatisfied dependency error for bean MongoTemplate which I inject in the concrete implementation of UProductRepository, called UProductRepositoryImpl.

public class UProductRepositoryImpl implements UProductRepositoryCustom {
    private final MongoTemplate mongoTemplate;

    @Autowired
    public UProductRepositoryImpl(MongoTemplate mongoTemplate) {
        this.mongoTemplate = mongoTemplate;
    }
}

org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.data.mongodb.core.MongoTemplate'

How may I expose MongoTemplate to the second worker process? Moreover, what would be a good way to approach something like this? Should I try to organize my components such that only the relevant ones are exposed to the worker process? Thanks for your attention!

Solution

Solution

Since the worker process must also be a Spring application (in order to allow for injecting repositories and such), its application context must be initialized as such. The web parameter is to prevent a proper web server being set up, since that is not necessary.

// Other configs..
@EnableAutoConfiguration
public class BackgroundWorker implements ApplicationRunner {

    @Autowired
    // Repositories..

    public static void main(String[] args)
    {
        new SpringApplicationBuilder(BackgroundWorker.class)
                .web(WebApplicationType.NONE)
                .run(args);
    }

Answered By – Kanghu

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published