Spring Boot and long running tasks - spring-boot

In my Spring Boot application I have to implement an import service. Users can submit a bunch of JSON files and application will try to import the data from these files. Depending on the data amount at JSON files the single import process can take a 1 or 2 hours.
I do not want to block the users during the import process so I plan to accept the task for importing and notify user that this data is scheduled for processing. I'll put the data into the queue and a free queue-consumer on the other end will start the import process. Also, I need to have a possibility to monitor a jobs in the queue, terminate them if needed.
Right now I'm thinking to use Embedded Apache ActiveMQ in order to introduce message producer and consumer logic but before this I'd like to ask - from the architecture point of view - is it a good choice for the described task or it can be implemented with a more appropriate tools.. like for example plain Spring #Async and so on ?

It is possible to treat files concurrently with Camel like this
from("file://incoming?maxMessagesPerPoll=1&idempotent=true&moveFailed=failed&move=processed&readLock=none").threads(5).process()
Take a look at http://camel.apache.org/file2.html
But i think that it is better for your requirements to use a standalone ActiveMQ, a standalone service to move files to ActiveMQ and standalone consumer to be capable to kill or restart each one independently.
It is better to use ActiveMQ as you said and you can easily create a service to move messages to a queue with Camel like this :
CamelContext context = new DefaultCamelContext();
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("vm://localhost?broker.persistent=true");
context.addComponent("test-jms", JmsComponent.jmsComponentAutoAcknowledge(connectionFactory));
context.addRoutes(new RouteBuilder() {
public void configure() {
// convertBodyTo to use TextMessage or maybe send them as file to the Queue from("file://testFolderPath").convertBodyTo(String.class).to("test-jms:queue:test.queue");
}
});
context.start();
Here some examples
http://www.programcreek.com/java-api-examples/index.php?api=org.apache.camel.component.jms.JmsComponent
https://skills421.wordpress.com/2014/02/08/sending-local-files-to-a-jms-queue/
https://github.com/apache/camel/blob/master/examples/camel-example-jms-file/src/main/java/org/apache/camel/example/jmstofile/CamelJmsToFileExample.java
https://github.com/apache/camel/tree/master/examples
To monitor and manage you can use jmx with VisualVM or Hawtio http://hawt.io/getstarted/index.html
http://camel.apache.org/camel-jmx.html
To consume you can use DefaultMessageListenerContainer with concurrent consumers on the queue and for this you need to change the prefetchPolicy on the ConnectionFactory of the DefaultMessageListenerContainer , Multithreaded JMS client ActiveMQ

Related

Is it possible to automatically create queues without RabbitAutoConfiguration.class? AMQP

I'm using 2.1.0.RELEASE version of Spring boot with AMQP. Unfortunetly I need to connect to several different RabbitMQ servers. I had to exclude RabbitAutoConfiguration.class besause due to changes in above version of spring it's impossible to start without one of the ConnectionFactory beans as primary, but even if I set one of them as #Primary, obviously it doesn't work, because how would amqp/spring-boot know which queue to create on which server...
so, is it possible to automatically create queues on different servers with auto configuration disabled?
Yes, you need a RabbitAdmin for each connection factory.
By default all components will be declared on all brokers, but you can add conditions. See Conditional Declaration.
By default, all queues, exchanges, and bindings are declared by all RabbitAdmin instances (assuming they have auto-startup="true") in the application context.
#Bean
public Queue queue1() {
Queue queue = new Queue("foo");
queue.setAdminsThatShouldDeclare(admin1());
return queue;
}

Spring Kafka disabling listening from a list of topics

We use spring kafka configuration to receive messages from upstream systems.
We have java configuration for topic configuration
#Bean(id="firstcontainer")
protected ConcurrentMessageListenerContainer createContainerInstance(...) {
//topics addition
}
#Bean(id="secondcontainer")
protected ConcurrentMessageListenerContainer createContainerInstance(...) {
//topics addition
}
#KafkaListener(firstcontainer)
public void listenerFirst(){
}
#KafkaListener(secondcontainer)
public void listenerSecond(){
}
This code works perfectly fine as we have seperate containerfactory.
Now we have requirement to spin up mulitple instances of this application where one instance will listen to firstContainer and secondContainer will be disabled
And For second instance, it will only enable secondContainer and disable firstContainer.
Can someone help to understand if it is possible to disable listening from a topic(list of topics)?
Your two instances (or many) can be identical and accept topic list from the external configuration. The #KafkaListener allows to do that.
There is Spring #Profile functionality, if you still want to keep several beans in your application. This way you should sever your #KafkaListener method to different classes and mark their component with an appropriate #Profile, which, again, can be activated externally.
The Apache Kafka has a concept as Consumer Group meaning that all consumers in the same group are joining to the broker, but only one of them will consume records from single partition in the topic. This way independently of the number of instances of your application you still will have a consistency because there is nothing to worry about duplicates in case of proper Kafka groups usage.

How to create an application to poll 10 JMX URI and store in DB in Spring

How to create an application to poll 50 JMX URI and store the mbeans in DB.
I have created a class which will connect to jmx server and fetch the mbeans value.
My question is how to trigger my created class and method to continues polling.
Moreover, I need two function to start and stop this polling anytime.
What can I use - Spring Scheduler, Spring Integration and how or should I create different class having thread and infinite loop.
Take a look at Spring Integration and its JMX Tree Polling Channel Adapter.
With Spring Scheduler (#Schedule annotation) it is easy to have a method that is invoked (for example) every minute. But it is not possible* to change (disable) that scheduling.
Anyway you could:
use the quarz-framework directly, then you could change the scheduling, or
do implement a dirty (but easy) hack:
Let the schueduler run, but disable the invocation of the real polling method:
private volantile boolean pollingEnabled;
#Schedule(fixedRate=1000)
public void pollTrigger() {
if (pollingEnabled) {
doPolling();
}
}
*more precise: to my knowlege there is no easy way

How to stop consumers

I made a simple Jms project with 2 java files names are MessageSender.java,MessageConsumer.java.one for sending messages to Activemq:Queue and another for consuming messages from Activemq:Queue.Deployed this project in Apache Tomcat.following code was consumer code.
ActiveMQConnectionFactory connectionFactory=new ActiveMQConnectionFactory("admin","admin","tcp://localhost:61617?jms.prefetchPolicy.queuePrefetch=1");
Connection connection=connectionFactory.createConnection();
final Session session=connection.createSession(true, Session.CLIENT_ACKNOWLEDGE);
Queue queue=session.createQueue("ThermalMap");
javax.jms.MessageConsumer consumer=session.createConsumer(queue);
//anonymous class
MessageListener listener = new MessageListener() {
#Override
public void onMessage(Message msg) {
// My business code
}
};
Later If I want to change consumer code,I don't want to stop Tomcatbecause If I stop Tomcat entire jms project should not work. So clients can't able to sent messages to Activemq:Queue.So I don't want to follow this way.
I am thinking, If I stop consumers through Activemq console page.I don't need to stop Tomcat So clients can able to send messages normally.For this I check AMQ console page,I didn't seen any consumers.
Is it correct way to do this.
If it is correct way, How can I do this.
can anyone suggest me.
Thanks.
Call the .close() method on your MessageConsumer.

Running Spring DMLC as CRON

Is there a way to Spring DMLC (DefaultMessageListenerContainer) to consume messages (say every 10 minutes) using CRON?
I don't want the messages to be picked up by Spring DMLC all the times.
Let's say a message is produced and dropped off into the JMS broker, I like the consumer (Spring DMLC) to pick up after some time for processing.
I am wondering if there is a way to configure Spring DMLC and Quartz?
Why do you need a DMLC in that case? If you use spring, a JMSTemplate might be what you are looking for.
void readOneMessageAndProcess() throws JmsException{
Message msg = jmsTemplate.receive("SOME.QUEUE");
// Process.
}
Then have Quartz, java timer, or a simple public static void main(String args[]) triggerd by a cron job run the method

Resources