PubSub with spring: know the message is publish or not? - spring-boot

My publisher code look like this:
public abstract class PubSubPublisher {
private static final Logger LOGGER = LoggerFactory.getLogger(PubSubPublisher.class);
private final PubSubTemplate pubSubTemplate;
protected PubSubPublisher(PubSubTemplate pubSubTemplate) {
this.pubSubTemplate = pubSubTemplate;
}
protected abstract String topic(String topicName);
public void publish(String topicName, String message) throws StatusRuntimeException {
LOGGER.info("Publishing to topic [{}]. Message: [{}]", topicName, message);
pubSubTemplate.publish(topicName, message);
}
}
My Component
#Component
public class HelloPubSubPublisher extends PubSubPublisher {
#Autowired
public HelloPubSubPublisher(PubSubTemplate pubSubTemplate) throws StatusRuntimeException{
super(pubSubTemplate);
}
#Override
protected String topic(String topicName) {
return topicName;
}
}
Now on my service layer how do i get weather i successful publish the message to topic or not, note all the google api are async which i am using.
try {
publisher.publish(topicName, payload);
}catch (Exception e) {
LOGGER.error("ioException occured: "+e);
throw new TopicNotFoundException();
}
Unfortunately, I am not able to capture the any error, program cursor is not going into the catch block.
Ultimately, I wanted to know weather the code is push the message into topic if not then I have to log it and throw that error to client, which is not happen with my current code with proper exception handling.
Any help or guidance is appreciated, thanks.

Using the function publish() you should be able to capture a future where you can check if the message was published or not.
You have an example of it on Google's PubSub documentation:
// Once published, returns a server-assigned message id (unique within the topic)
ApiFuture<String> future = publisher.publish(pubsubMessage);
// Add an asynchronous callback to handle success / failure
ApiFutures.addCallback(
future,
new ApiFutureCallback<String>() {
#Override
public void onFailure(Throwable throwable) {
if (throwable instanceof ApiException) {
ApiException apiException = ((ApiException) throwable);
// details on the API exception
System.out.println(apiException.getStatusCode().getCode());
System.out.println(apiException.isRetryable());
}
System.out.println("Error publishing message : " + message);
}
#Override
public void onSuccess(String messageId) {
// Once published, returns server-assigned message ids (unique within the topic)
System.out.println(messageId);
}
},
MoreExecutors.directExecutor());

Related

Stop RabbitMQ-Connection in Spring-Boot

I have a spring-boot application that pulls all the messages from a RabbitMQ-queue and then terminates. I use rabbitTemplate from the package spring-boot-starter-amqp (version 2.4.0), namely receiveAndConvert(). Somehow, I cannot get my application to start and stop again. When the rabbitConnectionFactory is created, it will never stop.
According to Google and other stackoverflow-questions, calling stop() or destroy() on the rabbitTemplate should do the job, but that doesn't work.
The rabbitTemplate is injected in the constructor.
Here is some code:
rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
Object msg = getMessage();
while (msg != null) {
try {
String name = ((LinkedHashMap) msg).get(propertyName).toString();
//business logic
logger.debug("added_" + name);
} catch (Exception e) {
logger.error("" + e.getMessage());
}
msg = getMessage();
}
rabbitTemplate.stop();
private Object getMessage() {
try {
return rabbitTemplate.receiveAndConvert(queueName);
} catch (Exception e) {
logger.error("" + e.getMessage());
return null;
}
}
So, how do you terminate the connection to RabbitMQ properly?
Thanks for your inquiry.
You can call resetConnection() on the CachingConnectionFactory to close the connection.
Or close() the application context.
If I were to do it , I would use #RabbitListener to receive the messages and RabbitListenerEndpointRegistry to start and stop the listener. Sample Code is given below
#EnableScheduling
#SpringBootApplication
public class Application implements ApplicationRunner {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
public static final String queueName = "Hello";
#Bean
public Queue hello() {
return new Queue(queueName);
}
#Autowired
private RabbitTemplate template;
#Scheduled(fixedDelay = 1000, initialDelay = 500)
public void send() {
String message = "Hello World!";
this.template.convertAndSend(queueName, message);
System.out.println(" [x] Sent '" + message + "'");
}
#Autowired
RabbitListenerEndpointRegistry registry;
#Override
public void run(ApplicationArguments args) throws Exception {
registry.getListenerContainer( Application.queueName).start();
Thread.sleep(10000L);
registry.getListenerContainer( Application.queueName).stop();
}
}
#Component
class Receiver {
#RabbitListener(id= Application.queueName,queues = Application.queueName)
public void receive(String in) {
System.out.println(" [x] Received '" + in + "'");
}
}

Flux Reactive Microservice - one microservice signal other microservice about backpressure

Two Springboot microservices need to interact with each other to achieve mass emailing feature. Microservice 1: CollectorService collects information about clients and
Microservice 2: NotificationService to send documents via SMTP service. NotificationService is unable to handle the load that CollectorService produces. Now I want to understand how NotificationService can signal CollectorService to slow down. My code looks like below currently.
CollectorSerivce calling NotificationService
final WebClient client = WebClient.builder().baseUrl(BASE_URL.get()).defaultHeaders(httpHeaders -> {
httpHeaders.set("requestId", requestId);
}).build();
Mono<List> responseFlux = client.post().uri(EXTERNAL_API_PATH.get() + "/withattFluxBackPressure")
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(message)).retrieve().bodyToMono(List.class);
NotificationService processing requests
#PostMapping(value = "/externalNotification/withattFluxBackPressure")
public List<NotificationResponse> sendMailMessageWAttFlux(#RequestBody List<EmailTemplate> mailMessages) throws Exception{
log.info("Processing email sending request async...");
// byte[] byteArrayResource = get file content from S3
List<NotificationResponse> response = new ArrayList<>();
Flux<NotificationResponse> responseFlux = Flux.fromIterable(mailMessages).flatMap(messages -> {
try {
return Flux.just(notificationService.sendMailWAtt(messages, byteArrayResource).map(NotificationResponse::error).orElse(NotificationResponse.success()));
} catch (IOException e) {
log.error("Exception", e);
return Flux.just(new NotificationResponse().error(e.getMessage()));
}
});
responseFlux.subscribe(new BaseSubscriber<NotificationResponse>() {
#Override
protected void hookOnSubscribe(Subscription subscription) {
log.info("called hookOnSubscribe......");
subscription.request(1);
}
#Override
protected void hookOnNext(NotificationResponse value) {
log.info("called hookOnNext.......{} ", value);
response.add(value);
request(1);
}
#Override
protected void hookOnComplete() {
log.info("called hookOnComplete.......");
}
#Override
protected void hookOnError(Throwable throwable) {
log.info("called hookOnError.......");
if(throwable instanceof ConnectException) {
log.error("called ConnectException.......");
}
if(throwable instanceof ResourceAccessException) {
log.error("called ResourceAccessException.......");
}
if(throwable instanceof ConnectTimeoutException) {
log.error("called ConnectTimeoutException.......");
}
if(throwable instanceof io.netty.channel.ConnectTimeoutException) {
log.error("called netty ConnectTimeoutException.......");
}
}
});
return response;
}```
1. When NotificationService overloads, how can it signal(backpressure) CollectorService to slow down? (Ideal scenario)
2. Alternatively, NotificationService processes 5 emails then signal/request CollectorService for the next 5.
Thanks for your time!

Is decorated function returned by Retry threadsafe?

I have a class that sends a message to a remote service as shown below.
I'm using resilience4j-retry to retry the network call. As the retry instance is thread safe according to the documentation, I'm creating it in the class level and reusing it.
public class RemoteMessageService {
Retry retry = Retry.of("RemoteMessageService", RetryConfig.custom()
.maxAttempts(5)
.retryExceptions(ProcessingException.class)
.intervalFunction(IntervalFunction.ofExponentialBackoff())
.build());
public void postMessageWithRetry(final String message){
Function<Integer, Void> postMessageFunction = Retry.decorateFunction(retry, this::postMessage);
try {
postMessageFunction.apply(message)
} catch (final ProcessingException e) {
LOG.warn("Got processing exception: {}", e.getMessage());
} catch (final Exception e) {
LOG.error("Got unknown exception: {}", e.getMessage());
}
}
private Void postMessage(final String message){
// Do a network call to send the message to a rest service
// throw ProcessingException in case of timeout
return null;
}
}
My question is if the decorated function returned by Retry.decorateFunction(retry, this::postMessage); is also thread safe?
In that case I could move this to class level instead of repeating it every time the postMessageWithRetry function is called.
After looking into the resilience4j-retry code, I found that the decorated function is in fact thread safe; as long as the function that we decorate in the first place is thread safe.
So I can rewrite the code as below since the postMessage function is thread safe, and therefor the decorated postMessageFunction function is also thread safe.
public class RemoteMessageService {
private final Retry retry = Retry.of("RemoteMessageService", RetryConfig.custom()
.maxAttempts(5)
.retryExceptions(ProcessingException.class)
.intervalFunction(IntervalFunction.ofExponentialBackoff())
.build());
private final Function<Integer, Void> postMessageFunction = Retry.decorateFunction(retry, this::postMessage);
public void postMessageWithRetry(final String message) {
try {
postMessageFunction.apply(message)
} catch (final ProcessingException e) {
LOG.warn("Got processing exception: {}", e.getMessage());
} catch (final Exception e) {
LOG.error("Got unknown exception: {}", e.getMessage());
}
}
private Void postMessage(final String message) {
// Do a network call to send the message to a rest service
// throw ProcessingException in case of timeout
return null;
}
}

Require assistance with simple pure Java 11 WebSocket client example

There appears to be very little Java 11 (pure Java non framework based) WebSocket client code examples on the web so I'm hoping StackOverflow can come to the rescue for me once again.
This is the closest I've found, but unfortunately to my (novice) eyes, it doesn't appear to be a complete solution in showing how to consume the data from the WebSocket listener.
Looking at the WebSocket.Listener implementation, the onText callback method I presume would provide what I need, but I'm struggling to figure out how to return the CompletionStage object and some sort of string data from the socket.
This is some test code I have so far.
Would appreciate assistance. Thanks
public class Main {
public static void main(String[] args) {
WebSocketClient wsc = new WebSocketClient();
wsc.startSocket("ws://demos.kaazing.com/echo");
int i = 0;
// Bad, very bad
do {} while (i == 0);
}
}
public class WebSocketClient implements WebSocket.Listener {
#Override
public void onOpen(WebSocket webSocket) {
//...
System.out.println("Go...Open".concat(
webSocket.getSubprotocol()));
}
#Override
public CompletionStage<?> onText(WebSocket webSocket, CharSequence data, boolean last) {
//...
System.out.println(data.toString());
// How do I return the CompletionStage object
// return CompletionStage<String>
}
#Override
public void onError(WebSocket webSocket, Throwable error) {
//..
System.out.println("Bad day! ".concat(webSocket.toString()));
}
void startSocket(String connection) {
CompletableFuture<WebSocket> server_cf = HttpClient.
newHttpClient().
newWebSocketBuilder().
buildAsync(URI.create(connection),
new WebSocketClient());
WebSocket server = server_cf.join();
server.sendText("Hello!", true);
}
}
Below you find a working example. I have made some changes to your code above:
onOpen needs to invoke request(1) on the websocket (invoking the default implementation) in order to receive further invocations.
moved method startSocket into the main method
replaced busy waiting with a count down latch
declared class WebSocketClient as a (static) inner class
but beyond these (cosmetic) changes the program follows your idea, i.e. first a websocket connection is build and after successful construction the text Hello! is sent to the echo server. This could also be done in method onOpen directly.
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.WebSocket;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.CountDownLatch;
public class Main {
public static void main(String[] args) throws Exception {
CountDownLatch latch = new CountDownLatch(1);
WebSocket ws = HttpClient
.newHttpClient()
.newWebSocketBuilder()
.buildAsync(URI.create("ws://demos.kaazing.com/echo"), new WebSocketClient(latch))
.join();
ws.sendText("Hello!", true);
latch.await();
}
private static class WebSocketClient implements WebSocket.Listener {
private final CountDownLatch latch;
public WebSocketClient(CountDownLatch latch) { this.latch = latch; }
#Override
public void onOpen(WebSocket webSocket) {
System.out.println("onOpen using subprotocol " + webSocket.getSubprotocol());
WebSocket.Listener.super.onOpen(webSocket);
}
#Override
public CompletionStage<?> onText(WebSocket webSocket, CharSequence data, boolean last) {
System.out.println("onText received " + data);
latch.countDown();
return WebSocket.Listener.super.onText(webSocket, data, last);
}
#Override
public void onError(WebSocket webSocket, Throwable error) {
System.out.println("Bad day! " + webSocket.toString());
WebSocket.Listener.super.onError(webSocket, error);
}
}
}
Btw, no supprotocol was negotiated, therefore method webSocket.getSubprotocol() returns an empty string. The output in the console is
onOpen using subprotocol
onText received Hello!
The pattern for managing a WebSocket response returning a CompletionStage is:
#Override
public CompletionStage<?> onText(WebSocket webSocket, CharSequence data, boolean last) {
// return inmmediately but response is geenrated lazyly.
return CompletableFuture.supplyAsync(() -> {
String response = "Received ...";
// do slow task. Access to database or access to a server.
return response;
});
}
This simple implementation only is recommended when the response is generated quickly.
#Override
public CompletionStage<?> onText(WebSocket webSocket, CharSequence data, boolean last) {
// fast response.
String response = "The text has " + data.length() + " chars";
return CompletableFuture.completedFuture(response);
}
I have had some trouble getting various examples working. Specifically, I had trouble finding examples that actually showed how to open, send, and receive simple text messages. One important piece was having a server to which to connect. Here is what I managed to make work.
package webSockets;
import java.io.IOException;
import java.net.URI;
import javax.websocket.CloseReason;
import javax.websocket.ContainerProvider;
import javax.websocket.Endpoint;
import javax.websocket.EndpointConfig;
import javax.websocket.MessageHandler;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;
public class SimpleWebsocketClient extends Endpoint {
private Session session;
public SimpleWebsocketClient() {}
public SimpleWebsocketClient(URI endpointURI) {
try {
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
container.connectToServer(this, endpointURI);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
#Override
public void onClose(Session session, CloseReason reason){
System.out.println("Disconnected as a result of "+ reason.getReasonPhrase());
}
#Override
public void onError(Session session, Throwable error){
System.out.println("Error communicating with server: " + error.getMessage());
}
#Override
public void onOpen(Session s, EndpointConfig config) {
System.out.println("Session opened");
session = s;
session.addMessageHandler(new MessageHandler.Whole<String>() {
#Override
public void onMessage(String msg) {
System.out.println("Text Message Received:" + msg);
}
});
try {
session.getBasicRemote().sendText("Hello there.");
session.getBasicRemote().sendText("Hope you are well!");
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public static void main(String...arg) {
URI uri = URI.create("ws://connect.websocket.in/v3/1?api_key=oCdCMcMPQpbvNjUIzqtvF1d2X2okWpDQj4AwARJuAgtjhzKxVEjQU6IdCjwm&notify_self");
new SimpleWebsocketClient(uri);
while(true) {}
}
}

Spring integration : testing async flows

I'm trying to write a test case for a scenario in which I send a message to a JMS endpoint and then the message is processed using Spring Integration. Here is a test case that works but its not entirely clear to me why it works. Here is the test:
public class MessageListenerTest {
#Autowired ApplicationContext context;
#Test
public void testEventListener() {
SubscribableChannel eventsChannel = (SubscribableChannel) context.getBean("events");
class TestMessageHandler implements MessageHandler {
public Boolean received = false;
#Override
public void handleMessage(Message<?> message) throws MessagingException {
received = true;
}
}
TestMessageHandler handler = new TestMessageHandler();
eventsChannel.subscribe(handler);
PollableChannel outputChannel = new QueueChannel();
PollingConsumer consumer = new PollingConsumer(outputChannel, handler);
consumer.setBeanFactory(context);
consumer.start();
String msg = "hello world!";
JmsTemplate template = (JmsTemplate) context.getBean("jmsTemplate");
template.convertAndSend("myQueue", msg);
outputChannel.receive(2000);
Assert.assertTrue(handler.received);
}
}
This tests that the message sent to the queue is received. The message is received by a SubscribableChannel named events. What is not clear to me is how the PollableChannel is connected to the SubscribableChannel. Is it because of TestMessageHandler? If so, how? If this is working entirely by accident, it would be useful if someone could fix this or provide a simpler test case for this scenario.
UPDATE: Based on the suggestions in the comments, here is a modified test case:
public class MessageListenerTest {
#Autowired ApplicationContext context;
#Test
public void testEventListener() throws InterruptedException {
SubscribableChannel eventsChannel = (SubscribableChannel) context.getBean("events");
final CountDownLatch countDownLatch = new CountDownLatch(1);
MessageHandler handler = new MessageHandler() {
#Override
public void handleMessage(Message<?> message) throws MessagingException {
countDownLatch.countDown();
}
};
eventsChannel.subscribe(handler);
String msg = "hello world!";
JmsTemplate template = (JmsTemplate) context.getBean("jmsTemplate");
template.convertAndSend("myQueue", msg);
Assert.assertTrue(countDownLatch.await(2, TimeUnit.SECONDS));
}
}
Your outputChannel just doesn't work. This channel is a test-case scope. so no one sends messages to it.
You can check that with the assert:
Assert.notNull(outputChannel.receive(2000));
It doesn't matter for how much channel the MessageHandler is subscribed. It just handles messages. So, it continues to handle messages from your events. And the binding to that inline outputChannel just is dead and doesn't matter for other application.

Resources