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