Optimise Consuming messages from rabbitmq using Spring Integration - spring-boot

I am attempting to build an IntegrationFlowFactory to easily build integration flows for passing events between application contexts.
Everything seems to work, and events are being published very quick.
However i cannot figure out why the consuming is so slow. Adding concurrentConsumers or changing prefetchCount does not seem to change anything.
Other posts talk about the network being slow, but as you can see in the RabbitConfig i am using localhost.
I have a repository with my spring integration example here:
https://github.com/teplyuska/spring-integration-example

Your problem is here:
Amqp.inboundGateway(getListenerContainer(queue, concurrentConsumers, prefetchCount)
Meanwhile your downstream flow is one-way and doesn't return any reply:
.handle(p -> {
UpdateSecretEvent payload = (UpdateSecretEvent) p.getPayload();
System.out.println("Account: " + payload.getAccountId() + " has secret: " + payload.getNewSecret());
})
.get();
or
.handle(p -> {
UpdateEmailEvent payload = (UpdateEmailEvent) p.getPayload();
System.out.println("Account: " + payload.getAccountId() + " has email: " + payload.getEmail());
})
.get();
So, that AmqpInboundGateway waits for the reply in its MessagingTemplate.sendAndReceive() for the private static final long DEFAULT_TIMEOUT = 1000L;
Switching to the Amqp.inboundAdapter() there does the trick.

Related

Spring Integration: Microsoft Outlook oauth2

i've a spring integration java application with a flow configured like this:
String emailStoreUri = emailProtocol + "://" + emailUsername + ":" + emailPassword + "#" + emailHost + ":" + emailPort + "/" + emailFolderInbox;
return IntegrationFlows.from(Mail.imapInboundAdapter(emailStoreUri)
.shouldMarkMessagesAsRead(emailShouldMarkMessagesAsRead)
.simpleContent(true).maxFetchSize(msgPerPoll)
.searchTermStrategy(new AcceptAllEmailStrategy())
.javaMailProperties(p -> {
p.put("mail.store.protocol", emailProtocol);
p.put("mail.debug", emailDebug);
p.put("mail.imaps.timeout", "5000");
p.put("mail.imaps.connectionpoolsize", "1");
p.put("mail.imaps.connectiontimeout", "5000");
p.put("mail.imaps.connectionpool.debug","true");
p.put("mail.debug", "true");
}).simpleContent(true),
e -> e.autoStartup(emailAutoStart).poller(pollerMetadata))
.channel(MessageChannels.rendezvous("inboundEmailChannel")).log("DEBUG").get();
}
This just work for basi auth, how to fix to let this codw work with OAUTH2?
I'm searching online but i didn't find anything about this problem
I somehow think that this is your Gitter question as well: https://gitter.im/spring-projects/spring-integration?at=63ce9304624f3f4330280089.
So, to have a full context over here, please, look into this GH issue: https://github.com/spring-projects/spring-integration-samples/issues/341.
To be precise: you need to implement an Authenticator to obtain OAuth token against the user. Feel free to raise a GH issue, so we will document this approach. Although this has nothing to do with Spring Integration - plain Java Mail feature, - too many people are asking it in Spring Integration context.
Such an Authenticator has to be injected into an ImapMailReceiver via its property:
/**
* Optional, sets the Authenticator to be used to obtain a session. This will not be used if
* {#link AbstractMailReceiver#setSession} has been used to configure the {#link Session} directly.
* #param javaMailAuthenticator The javamail authenticator.
* #see #setSession(Session)
*/
public void setJavaMailAuthenticator(Authenticator javaMailAuthenticator) {
Don't forget to set Java Mail mail.imap.auth.mechanisms=XOAUTH2 property!

Listener for NATS JetStream

Can some one help how to configure NATS jet stream subscription in spring boot asynchronously example: looking for an equivalent annotation like #kafkalistener for Nats jetstream
I am able to pull the messages using endpoint but however when tried to pull messages using pushSubscription dispatcherhandler is not invoked. Need to know how to make the listener to be active and consume messages immediately once the messages are published to the subject.
Any insights /examples regarding this will be helpful, thanks in advance.
I don't know what is your JetStream retention policy, neither the way you want to subscribe. But I have sample code for WorkQueuePolicy push subscription, wish this will help you.
public static void subscribe(String streamName, String subjectKey,
String queueName, IMessageHandler iMessageHandler) throws IOException,
InterruptedException, JetStreamApiException {
long s = System.currentTimeMillis();
Connection nc = Nats.connect(options);
long e = System.currentTimeMillis();
logger.info("Nats Connect in " + (e - s) + " ms");
JetStream js = nc.jetStream();
Dispatcher disp = nc.createDispatcher();
MessageHandler handler = (msg) -> {
try {
iMessageHandler.onMessageReceived(msg);
} catch (Exception exc) {
msg.nak();
}
};
ConsumerConfiguration cc = ConsumerConfiguration.builder()
.durable(queueName)
.deliverGroup(queueName)
.maxDeliver(3)
.ackWait(Duration.ofMinutes(2))
.build();
PushSubscribeOptions so = PushSubscribeOptions.builder()
.stream(streamName)
.configuration(cc)
.build();
js.subscribe(subjectKey, disp, handler, false, so);
System.out.println("NatsUtil: " + durableName + "subscribe");
}
IMessageHandler is my custom interface to handle nats.io received messages.
First, configure the NATS connection. Here you will specify all your connection details like server address(es), authentication options, connection-level callbacks etc.
Connection natsConnection = Nats.connect(
new Options.Builder()
.server("nats://localhost:4222")
.connectionListener((connection, eventType) -> {})
.errorListener(new ErrorListener(){})
.build());
Then construct a JetStream instance
JetStream jetStream = natsConnection.jetStream();
Now you can subscribe to subjects. Note that JetStream consumers can be durable or ephemeral, can work according to push or pull logic. Please refer to NATS documentation (https://docs.nats.io/nats-concepts/jetstream/consumers) to make the appropriate choice for your specific use case. The following example constructs a durable push consumer:
//Subscribe to a subject.
String subject = "my-subject";
//queues are analogous to Kafka consumer groups, i.e. consumers belonging
//to the same queue (or, better to say, reading the same queue) will get
//only one instance of each message from the corresponding subject
//and only one of those consumers will be chosen to process the message
String queueName = "my-queue";
//Choosing delivery policy is analogous to setting the current offset
//in a partition for a consumer or consumer group in Kafka.
DeliverPolicy deliverPolicy = DeliverPolicy.New;
PushSubscribeOptions subscribeOptions = ConsumerConfiguration.builder()
.durable(queueName)
.deliverGroup(queueName)
.deliverPolicy(deliverPolicy)
.buildPushSubscribeOptions();
Subscription subscription = jetStream.subscribe(
subject,
queueName,
natsConnection.createDispatcher(),
natsMessage -> {
//This callback will be called for incoming messages
//asynchronously. Every subscription configured this
//way will be backed by its own thread, that will be
//used to call this callback.
},
true, //true if you want received messages to be acknowledged
//automatically, otherwise you will have to call
//natsMessage.ack() manually in the above callback function
subscribeOptions);
As for the declarative API (i.e. some form of #NatsListener annotation analogous to #KafkaListener from Spring for Apache Kafka project), there is none available out of the box in Spring. If you feel like you absolutely need it, you can write one yourself, if you are familiar with Spring BeanPostProcessor-s or other extension mechanism that can help to do that. Alternatively you can refer to 3rd party libs, it looks like a bunch of people (including myself) felt a bit uncomfortable when switching from Kafka to NATS, so they tried to bring the usual way of doing things with them from the Kafka world. Some examples can be found on github:
https://github.com/linux-china/nats-spring-boot-starter,
https://github.com/dstrelec/nats
https://github.com/amalnev/declarative-nats-listeners
There may be others.

webflux Mono response empty

I have a very simple spring webflux rest endpoint in my project.
#Bean
public RouterFunction authRoute() {
return RouterFunctions.route(POST("/auth/signin").and(accept(APPLICATION_JSON)), this::signIn)
.andRoute(POST("/auth/signup").and(accept(APPLICATION_JSON)), this::signUp)
.andRoute(POST("/auth/test").and(accept(APPLICATION_JSON)), this::test);
}
And /auth/test endpoint just reply back with the username supplied.
public Mono<ServerResponse> test(ServerRequest request) {
System.out.println("Start test ");
Mono<JwtRequest> jwtRequestMono = request.bodyToMono(JwtRequest.class);
jwtRequestMono.subscribe(v -> System.out.println(v.getUsername() + ":" + v.getPassword()));
return jwtRequestMono
.flatMap(j -> ServerResponse.ok().contentType(APPLICATION_JSON).bodyValue(j.getUsername()));
}
The problem I am facing is that the response body is empty, it should be the username. I also verified that when I return the hardcoded string, it passes. It fails when I depend on jwtRequestMono.flatMap(...
This line is almost certainly your downfall:
jwtRequestMono.subscribe(v -> System.out.println(v.getUsername() + ":" + v.getPassword()));
Your request can't be subscribed to multiple times - so you subscribe to it on this line (which works and prints out the values as expected), then the framework subscribes to it, and it blows up. I'd expect to see an exception and a 500 response returned when this happens by default, so chances are you're swallowing an exception somewhere.
Never subscribe within your own application. That's the frameworks job.
Instead, if you want to have a "side-effect" where you print the values as they come in, then use doOnNext() as part of your reactive chain:
return jwtRequestMono
.doOnNext(v -> System.out.println(v.getUsername() + ":" + v.getPassword()))
.flatMap(j -> ServerResponse.ok().contentType(APPLICATION_JSON).bodyValue(j.getUsername()));

How to process Observable<Response>

I have one local spring boot application which is hitting another PCF deployed application. The PCF application is giving me list of Student.
I am hitting the same using:
Observable<Response> result = RxObservable.newClient()
.target(url)
.request()
.rx()
.get();
Now I am not able to get my List<Student> back from result Observable.
Tried lots of approaches but nothing really working i.e. subscribing to result etc etc.
So after struggling for few hours below is the solution for now.
Observable observable = result.map(response -> response.readEntity(List.class));
DeferredResult<ResponseEntity<Response>> deferredResult = new DeferredResult(Duration.ofMillis(10000L).toMillis());
observable.subscribe((response) -> {
ResponseEntity<Response> responseData = new ResonseEntity(response, HttpStatus.OK);
deferredResult.setResult(responseData);
}, deferredResult::setErrorResult);
Please suggest, if it can be improved.
Thanks

What is the proper way to add Timer (for Task Schedule) in Spring 3+Tiles based web application?

I want to know if there is any proper way to add timer for task schedule (it will be count up) in Spring 3 + Tiles that works accurate. I have tried many options like jquery timer + (Client side) Quartz (Server side Threading), But though it is not accurate and somewhat we can say it is bad practice for web application.
What I exactly want (want to manage) is in my Web application(Spring 3 + Tiles), When user Click on Timer start, It should be started at client side and timer should be continued until user click on stop, however user could do any other things (Like navigation to any other pages) in web application but timer should be working in static way. There are many issues as if only I implement timer at client side (using cookies ,jquery session client side) than I have to manage if user navigate to another page then again timer will have to start from previous time that has been stored in cookies but doing this results in loss of seconds during request response processes.So I tried also to implement server side timer using quartz but again I have to sync it with client side timer at every click in web application . So again it is bad practice what I feel.
So Is there any thing that I can introduce in Spring 3 + tiles that can be static and can hold timer in static way.
Thanx in Advance.
Ok so you need Server Push in simple words.You can use Atmosphere for acheving this.
For integrating atmosphere with Spring MVC you can check this sample spring-web-mvc-atmosphere.after integration you just need to do this on your server side.
#RequestMapping(value = "/websockets", method = RequestMethod.GET)
#ResponseBody
public void websockets(final AtmosphereResource event) {
AtmosphereUtils.suspend(event);
final Broadcaster bc = event.getBroadcaster();
bc.scheduleFixedBroadcast(new Callable<String>() {
public String call() throws Exception {
return (new Date()).toString();
}
}, 1, TimeUnit.SECONDS);
}
And from client side:
function startTimer() {
var callbackAdded = false;
function callback(response)
{
$.atmosphere.log('info', ["response.state: " + response.state]);
$.atmosphere.log('info', ["response.transport: " + response.transport]);
if (response.transport != 'polling' && response.state != 'connected' && response.state != 'closed') {
$.atmosphere.log('info', ["response.responseBody: " + response.responseBody]);
if (response.status == 200) {
var data = response.responseBody;
if (data) {
$("#date").text(data);
}
}
}
}
$.atmosphere.subscribe("${pageContext.request.contextPath}/user/websockets",
!callbackAdded? callback : null,
$.atmosphere.request = {transport: 'websocket'});
connectedEndpoint = $.atmosphere.response;
callbackAdded = true;
};
Just suspend the get request and broadcast the current time perodically and you can extend this according to you need I have just given you a raw idea.Hope this helps.

Resources