I am relatively new to Redis Pub/Sub. I have integrated this recently in my Spring Boot application.
Redis Pub/Sub configuration is as follows:
#Configuration
public class RedisPubSubConfiguration {
#Bean
public RedisMessageListenerContainer messageListenerContainer(RedisConnectionFactory
connectionFactory,
#Qualifier("topicAdapterPair")
List<Pair
<Topic,
MessageListenerAdapter>>
channelAdaperPairList) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
for (Pair<Topic, MessageListenerAdapter> chanelAdapterPair : channelAdaperPairList) {
container.addMessageListener(chanelAdapterPair.getValue(),
chanelAdapterPair.getKey());
}
container.setConnectionFactory(connectionFactory);
return container;
}
#Bean("msg-listener-adptr-1")
public MessageListenerAdapter messageListnerAdapter1(
#Qualifier("message-listener-1")
MessageListener listener) {
return new MessageListenerAdapter(listener, REDIS_RECEIVER_METHOD_NAME);
}
#Bean("message-listener-1")
public MessageListener messageListener1(ManagerProxy managerProxy) {
return new MessageListener1(managerProxy);
}
#Bean("message-sender-1")
public MessageSender messageSender1(RedisTemplate redisTemplate,
#Value("${chnlTopicName1}")
String channelTopicName) {
return new MessageSender1(redisTemplate, channelTopicName);
}
#Bean
#Qualifier("topicAdapterPair")
public Pair<Topic, MessageListenerAdapter> getTopicListenerAdapterpair1(
#Value("${chnlTopicName1}") String channelTopicName,
#Qualifier("msg-listener-adptr-1")
MessageListenerAdapter messageListenerAdapter) {
return Pair.of(new ChannelTopic(channelTopicName), messageListenerAdapter);
}
#Bean("msg-listener-adptr-2")
public MessageListenerAdapter messageListnerAdapter2(
#Qualifier("message-listener-2")
MessageListener listener) {
return new MessageListenerAdapter(listener, REDIS_RECEIVER_METHOD_NAME);
}
#Bean("message-listener-2")
public MessageListener messageListener2(NotificationServiceImpl notificationService) {
return new MessageListener2(notificationService);
}
#Bean("message-sender-2")
public MessageSender messageSender2(RedisTemplate redisTemplate,
#Value("${chnlTopicName2}")
String channelTopicName) {
return new MessageSender2(redisTemplate, channelTopicName);
}
#Bean
#Qualifier("topicAdapterPair")
public Pair<Topic, MessageListenerAdapter> getTopicListenerAdapterPair2(
#Value("${chnlTopicName2}") String channelTopicName,
#Qualifier("msg-listener-adptr-2")
MessageListenerAdapter messageListenerAdapter) {
return Pair.of(new ChannelTopic(channelTopicName), messageListenerAdapter);
}
}
MessageSender2 is as follows:
public class MessageSender2 implements MessageSender<MyDTO> {
private final RedisTemplate<String, Object> redisTemplate;
private final String chanelName;
public MessageSender2(
RedisTemplate<String, Object> redisTemplate,
String chanelName) {
this.redisTemplate = redisTemplate;
this.chanelName = chanelName;
}
#Override
public void send(MyDTO myDTO) {
redisTemplate.convertAndSend(chanelName, myDTO);
}
}
MessageListener2 is as follows:
public class MessageListener2 implements MessageListener<EventDTO> {
private static final Logger LOGGER = LoggerFactory
.getLogger(MessageListener2.class);
private final NotificationService notificationService;
public MessageListener1(NotificationServiceImpl notificationService) {
this.notificationService = notificationService;
}
#Override
public void receiveMessage(MyDTO message) {
LOGGER.info("Received message : {} ", message); <--HERE MESSAGE IS NOT COMING EVEN AFTER PUBLISHING MESSAGE TO THE ASSOCIATED TOPIC FROM PUBLISHER
Type type = message.getType();
...
}
}
MessageSender1 is as follows:
public class MessageSender1 implements MessageSender<String> {
private final RedisTemplate<String, Object> redisTemplate;
private final String chanelName;
public MessageSender1(
RedisTemplate<String, Object> redisTemplate,
String chanelName) {
this.redisTemplate = redisTemplate;
this.chanelName = chanelName;
}
#Override
public void send(String message) {
redisTemplate.convertAndSend(chanelName, message);
}
}
Associated listener is follows:
public class MessageListener1 implements MessageListener<String> {
private static final Logger LOGGER = LoggerFactory
.getLogger(MessageListener1.class);
private final ManagerProxy managerProxy;
public MessageListener1(ManagerProxy managerProxy) {
this.managerProxy = managerProxy;
}
public void receiveMessage(String message) {
LOGGER.info("Received message : {} ", message);
managerProxy.refresh();
}
}
Here though MessageSender1 and associated message listener are working fine, I don't understand what I did with MessageSender2 and associated listener, because of which I am not able to receive message in the listener.
Related
What I am trying to do? : I am new to Spring Integration and already have read many similar questions regarding error handling but I don't understand how to catch exceptions using error-channel?
What I have done so far:
#EnableIntegration
#IntegrationComponentScan
#Configuration
public class TcpClientConfig implements ApplicationEventPublisherAware {
private ApplicationEventPublisher applicationEventPublisher;
private final ConnectionProperty connectionProperty;
#Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
TcpClientConfig(ConnectionProperty connectionProperty) {
this.connectionProperty = connectionProperty;
}
#Bean
public AbstractClientConnectionFactory clientConnectionFactory() {
TcpNioClientConnectionFactory tcpNioClientConnectionFactory =
getTcpNioClientConnectionFactoryOf(
connectionProperty.getPrimaryHSMServerIpAddress(),
connectionProperty.getPrimaryHSMServerPort());
final List<AbstractClientConnectionFactory> fallBackConnections = getFallBackConnections();
fallBackConnections.add(tcpNioClientConnectionFactory);
final FailoverClientConnectionFactory failoverClientConnectionFactory =
new FailoverClientConnectionFactory(fallBackConnections);
return new CachingClientConnectionFactory(
failoverClientConnectionFactory, connectionProperty.getConnectionPoolSize());
}
#Bean
DefaultTcpNioSSLConnectionSupport connectionSupport() {
final DefaultTcpSSLContextSupport defaultTcpSSLContextSupport =
new DefaultTcpSSLContextSupport(
connectionProperty.getKeystorePath(),
connectionProperty.getTrustStorePath(),
connectionProperty.getKeystorePassword(),
connectionProperty.getTruststorePassword());
final String protocol = "TLSv1.2";
defaultTcpSSLContextSupport.setProtocol(protocol);
return new DefaultTcpNioSSLConnectionSupport(defaultTcpSSLContextSupport, false);
}
#Bean
public MessageChannel outboundChannel() {
return new DirectChannel();
}
#Bean
#ServiceActivator(inputChannel = "outboundChannel")
public MessageHandler outboundGateway(AbstractClientConnectionFactory clientConnectionFactory) {
TcpOutboundGateway tcpOutboundGateway = new TcpOutboundGateway();
tcpOutboundGateway.setConnectionFactory(clientConnectionFactory);
return tcpOutboundGateway;
}
#Bean
#ServiceActivator(inputChannel = "error-channel")
public void handleError(ErrorMessage em) {
throw new RuntimeException(String.valueOf(em));
}
private List<AbstractClientConnectionFactory> getFallBackConnections() {
final int size = connectionProperty.getAdditionalHSMServersConfig().size();
List<AbstractClientConnectionFactory> collector = new ArrayList<>(size);
for (final Map.Entry<String, Integer> server :
connectionProperty.getAdditionalHSMServersConfig().entrySet()) {
collector.add(getTcpNioClientConnectionFactoryOf(server.getKey(), server.getValue()));
}
return collector;
}
private TcpNioClientConnectionFactory getTcpNioClientConnectionFactoryOf(
final String ipAddress, final int port) {
TcpNioClientConnectionFactory tcpNioClientConnectionFactory =
new TcpNioClientConnectionFactory(ipAddress, port);
tcpNioClientConnectionFactory.setUsingDirectBuffers(true);
tcpNioClientConnectionFactory.setDeserializer(new CustomDeserializer());
tcpNioClientConnectionFactory.setApplicationEventPublisher(applicationEventPublisher);
tcpNioClientConnectionFactory.setSoKeepAlive(true);
tcpNioClientConnectionFactory.setConnectTimeout(connectionProperty.getConnectionTimeout());
tcpNioClientConnectionFactory.setSoTcpNoDelay(true);
tcpNioClientConnectionFactory.setTcpNioConnectionSupport(connectionSupport());
return tcpNioClientConnectionFactory;
}
}
Gateway
#Component
#MessagingGateway(defaultRequestChannel = "outboundChannel",errorChannel ="error-channel" )
public interface TcpClientGateway {
String send(String message);
}
Also currently, I am facing
required a bean of type org.springframework.messaging.support.ErrorMessage that could not be found
I need some assistance!
Thanking you in advance,
EDIT
#AllArgsConstructor
#Service
public class AsyncNonBlockingClient implements Connector {
TcpClientGateway tcpClientGateway;
#Override
public String send(final String payload) {
return tcpClientGateway.send(payload);
}
}
See documentation about messaging annotation:
Your problem is here: https://docs.spring.io/spring-integration/docs/current/reference/html/configuration.html#annotations_on_beans
#Bean
#ServiceActivator(inputChannel = "error-channel")
public void handleError(ErrorMessage em) {
This is a plain POJO method, therefore it cannot be marked with a #Bean. You use a #Bean really for beans to expose. Then you decide if that has to be a #ServiceActivator or not. So, just remove #Bean from this method and your error-channel consumer should be OK.
When trying to implement a DistributedCommandBus using Spring Cloud, I am getting the following error intermittently. I have reason to believe that there is some sort of race condition happening with the auto-configuration of my aggregate root class, its command handlers, and my configuration bean class.
org.axonframework.commandhandling.NoHandlerForCommandException: No
node known to accept.
I am using Axon Version 3.3.5.
Here is my configurations class:
#Configuration
#AutoConfigureBefore(CustomerAggregate.class)
public class AxonConfig {
#Value("${mongo.servers}")
private String mongoUrl;
#Value("${mongo.db}")
private String mongoDbName;
#Value("${axon.events.collection.name}")
private String eventsCollectionName;
#Value("${axon.snapshot.collection.name}")
private String snapshotCollectionName;
#Value("${axon.saga.collection.name}")
private String sagaCollectionName;
#Bean
#Primary
public CommandGateway commandGateway(#Qualifier("distributedBus") DistributedCommandBus commandBus) throws Exception {
return new DefaultCommandGateway(commandBus, new IntervalRetryScheduler(Executors.newSingleThreadScheduledExecutor(), 1000, 10));
}
#Bean
#Primary
#Qualifier("springCloudRouter")
public CommandRouter springCloudCommandRouter(DiscoveryClient client, Registration localServiceInstance) {
return new SpringCloudCommandRouter(client, localServiceInstance, new AnnotationRoutingStrategy());
}
#Bean
#Primary
#Qualifier("springCloudConnector")
public SpringHttpCommandBusConnector connector() {
return new SpringHttpCommandBusConnector(new SimpleCommandBus(), new RestTemplate(), new JacksonSerializer());
}
#Bean
#Primary
#Qualifier("distributedBus")
public DistributedCommandBus springCloudDistributedCommandBus(#Qualifier("springCloudRouter") CommandRouter router) {
return new DistributedCommandBus(router, connector());
}
#Bean
#Primary
public AggregateFactory<CustomerAggregate> aggregateFactory(){
return new GenericAggregateFactory<CustomerAggregate>(CustomerAggregate.class);
}
#Bean
#Primary
public EventCountSnapshotTriggerDefinition countSnapshotTriggerDefinition(){
return new EventCountSnapshotTriggerDefinition(snapShotter(), 3);
}
#Bean
#Primary
public Snapshotter snapShotter(){
return new AggregateSnapshotter(eventStore(), aggregateFactory());
}
#Bean
#Primary
public EventSourcingRepository<CustomerAggregate> customerAggregateRepository(){
return new EventSourcingRepository<>(aggregateFactory(), eventStore(), countSnapshotTriggerDefinition());
}
#Bean(name = "axonMongoTemplate")
public MongoTemplate axonMongoTemplate() {
return new DefaultMongoTemplate(mongoClient(), mongoDbName)
.withDomainEventsCollection(eventsCollectionName)
.withSnapshotCollection(snapshotCollectionName)
.withSagasCollection(sagaCollectionName);
}
#Bean
public MongoClient mongoClient() {
MongoFactory mongoFactory = new MongoFactory();
mongoFactory.setMongoAddresses(Arrays.asList(new ServerAddress(mongoUrl)));
return mongoFactory.createMongo();
}
#Bean
#Primary
public MongoEventStorageEngine engine() {
return new MongoEventStorageEngine(new JacksonSerializer(), null, axonMongoTemplate(), new DocumentPerEventStorageStrategy());
}
#Bean
#Primary
public EventStore eventStore() {
return new EmbeddedEventStore(engine());
}
}
And here is my aggregate class with command handlers:
#Aggregate(repository = "customerAggregateRepository")
public class CustomerAggregate {
Logger logger = LoggerFactory.getLogger(this.getClass());
#AggregateIdentifier
private String id;
private String firstName;
private String lastName;
private String email;
private CustomerAggregate() {}
public String getId() {
return id;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public String getEmail() {
return email;
}
#CommandHandler
public CustomerAggregate(CreateCustomer cmd) {
logger.debug("Received creation command: " + cmd.toString());
apply(new CustomerCreated(cmd.getId(),cmd.getFirstName(),cmd.getLastName(), cmd.getEmail()));
}
#CommandHandler
public void on(UpdateCustomer cmd) {
logger.debug("Received update command: " + cmd.toString());
apply(new CustomerUpdated(this.id,cmd.getFirstName(),cmd.getLastName(), cmd.getEmail()));
}
#CommandHandler
public void on(UpdateCustomerEmail cmd) {
logger.debug("Received update command for existing customer: " + cmd.toString());
apply(new CustomerUpdated(cmd.getId(), this.firstName, this.lastName, cmd.getEmail()));
}
// Various event handlers...
}
Any help is much appreciated.
I am using rabbit mq 3.7.4 and have a queue with x-max-length:3 and x-overflow:reject-publish, I am trying to redirect those messages which comes once queue reaches it's max limit (i.efrom 4th message ...nth message) to a deadletter queue but was unable to achieve.
kibndly help with the same
My configuration:
#Configuration
#EnableAutoConfiguration
public abstract class AMQPConfig {
#Value("${overflow-queue.exchange}")
private String queueExchange;
#Value("${overflow-queue.routingkey}")
private String throttleRoutingKey;
#Value("${overflow.queue}")
private String queue;
/**
* abstract ampqTemplate method
*/
public abstract AmqpTemplate getAmqpTemplate();
#Bean
public MessageConverter jsonMessageConverter() {
return new Jackson2JsonMessageConverter();
}
#Bean
public TopicExchange salesExchange() {
return new TopicExchange(queueExchange);
}
#Bean
public Queue salesQueue() {
return //QueueBuilder.durable(throttleQueue)
QueueBuilder.durable(queue)
.withArgument("x-max-length", 3)
.withArgument("x-overflow", "reject-publish")
.withArgument("x-dead-letter-exchange",queueExchange)
.withArgument("x-dead-letter-routing-key","deadletter-routing-key")
.build();
}
#Bean
public Binding declareSalesQueueBinding() {
return BindingBuilder.bind(salesQueue()).to(salesExchange()).with(queue);//with(throttleQueue);
}
#Bean
public MappingJackson2MessageConverter consumerJackson2MessageConverter() {
return new MappingJackson2MessageConverter();
}
#Bean
public DefaultMessageHandlerMethodFactory messageHandlerMethodFactory() {
DefaultMessageHandlerMethodFactory factory = new DefaultMessageHandlerMethodFactory();
factory.setMessageConverter(consumerJackson2MessageConverter());
return factory;
}
}
MY PRODUCER:
#Service
public class Producer {
private static long sentMessageCount =0L;
#Autowired
private AmqpTemplate rabbitTemplate;
#Value("${overflow.queue}")
String queueName;
#Scheduled(initialDelay = 5000, fixedRate = 10)
public void queueSender() {
long x=++sentMessageCount;
rabbitTemplate.convertAndSend(queueName,"{'empId':'"+x+"','empName':'raj'}");
}
}
Springboot RabbitMq Consumer consuming only at first time.please help me to get the configurations right and how can configure multiple listners.I am developing an Automated Mapping solution for which i Execute various jobs .and in a need to put those jobs in queue
Here's my application class:Application.java
#SpringBootApplication
#ComponentScan(basePackages = { "com.fractal.sago", "com.fractal.grpc" })
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
RabbitMqConfig class:
#Configuration
public class RabbitMqConfig {
public final static String JOB_QUEUE_NAME = "jobQueue";
public final static String JOB_EXCHANGE_NAME = "jobExchange";
#Bean
Queue jobQueue() {
return new Queue(JOB_QUEUE_NAME, true);
}
#Bean
DirectExchange jobExchange() {
return new DirectExchange(JOB_EXCHANGE_NAME);
}
#Bean
Binding jobBinding(DirectExchange directExchange) {
return BindingBuilder.bind(jobQueue()).to(jobExchange()).with(jobQueue().getName());
}
#Bean
SimpleMessageListenerContainer jobQueueContainer(ConnectionFactory connectionFactory,
MessageListenerAdapter joblistenerAdapter) {
SimpleMessageListenerContainer jobQueueContainer = new SimpleMessageListenerContainer();
jobQueueContainer.setConnectionFactory(connectionFactory);
jobQueueContainer.setQueueNames(JOB_QUEUE_NAME);
jobQueueContainer.setMessageListener(joblistenerAdapter);
return jobQueueContainer;
}
#Bean
MessageListenerAdapter joblistenerAdapter(JobQueueConsumer messageReceiver) {
MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter(messageReceiver, "receiveMessage");
messageListenerAdapter.setMessageConverter(producerJackson2MessageConverter());
return messageListenerAdapter;
}
#Bean
public Jackson2JsonMessageConverter producerJackson2MessageConverter() {
return new Jackson2JsonMessageConverter();
}
}
producer : JobProducer
#Component
public class JobQueueProducer {
#Autowired
RabbitTemplate rabbitTemplate;
public void sendMessage(String message) {
Message messageToSend = MessageBuilder.withBody(message.getBytes())
.setDeliveryMode(MessageDeliveryMode.PERSISTENT).build();
rabbitTemplate.convertAndSend(RabbitMqConfig.JOB_EXCHANGE_NAME, RabbitMqConfig.JOB_QUEUE_NAME, messageToSend);
//rabbitTemplate.convertAndSend(RabbitMqConfig.JOB_QUEUE_NAME, messageToSend);
}
}
Consumer :JobQueueConsumer
enter code here
#Component
public class JobQueueConsumer implements MessageListener {
#Autowired
SagoAlgo sagoAlgo;
#Autowired
CCDMappingService ccdMappingService;
#RabbitListener(queues = { RabbitMqConfig.JOB_QUEUE_NAME })
public void receiveMessage(Message message) throws SQLException {
System.out.println("Received Message: " + new String(message.getBody()));
Integer jobId = Integer.parseInt(new String(message.getBody()));
System.out.println(jobId);
CCDMappingVO ccdVo =ccdMappingService.fetchCCDWithCategoriesById(jobId);
sagoAlgo.execAlgo(ccdVo); //my Algo to be executed
}
//when I implement MessageListener default method to be executed
public void onMessage(Message message) {
// System.out.println("Received Message: " + new
// String(message.getBody()));
}
}
I have one server and number of clients, server will send response and waits for acknowledgement, additionally I want to hold that connection forever for next message and acknowledgement how should i create these connection in Spring Integration. I read about Spring integration, i couldn't find out the solution for holding the connection.
public class ClientCall {
public static void main(String[] args) {
#SuppressWarnings("resource")
ApplicationContext ctx = new AnnotationConfigApplicationContext(GatewayConfig.class);
GatewayService gatewayService = ctx.getBean(GatewayService.class);
//int i=0;
Message message = new Message();
/*while(i<4)
{*/
message.setPayload("It's working");
gatewayService.sendMessage(message);
/* i++;
}*/
}
}
#Service
public interface GatewayService<T> {
public void sendMessage(final T payload);
public void receiveMessage(String response);
}
#EnableIntegration
#IntegrationComponentScan
#Configuration
#ComponentScan(basePackages = "com.gateway.service")
public class GatewayConfig {
// #Value("${listen.port:6788}")
private int port = 6785;
#Autowired
private GatewayService<Message> gatewayService;
#MessagingGateway(defaultRequestChannel = "sendMessageChannel")
public interface Gateway {
void viaTcp(String payload);
}
#Bean
public AbstractClientConnectionFactory clientCF() {
TcpNetClientConnectionFactory clientConnectionFactory = new TcpNetClientConnectionFactory("localhost",this.port);
clientConnectionFactory.setSingleUse(true);
return clientConnectionFactory;
}
#Bean
#ServiceActivator(inputChannel = "sendMessageChannel")
public MessageHandler tcpOutGateway(AbstractClientConnectionFactory connectionFactory) {
TcpOutboundGateway outGateway = new TcpOutboundGateway();
outGateway.setConnectionFactory(connectionFactory);
outGateway.setAsync(true);
outGateway.setOutputChannel(receiveMessageChannel());
outGateway.setRequiresReply(true);
outGateway.setReplyChannel(receiveMessageChannel());
return outGateway;
}
#Bean
public MessageChannel sendMessageChannel() {
DirectChannel channel = new DirectChannel();
return channel;
}
#Bean
public MessageChannel receiveMessageChannel() {
DirectChannel channel = new DirectChannel();
return channel;
}
#Transformer(inputChannel = "receiveMessageChannel", outputChannel = "processMessageChannel")
public String convert(byte[] bytes) {
return new String(bytes);
}
#ServiceActivator(inputChannel = "processMessageChannel")
public void upCase(String response) {
gatewayService.receiveMessage(response);
}
#Transformer(inputChannel = "errorChannel", outputChannel = "processMessageChannel")
public void convertError(byte[] bytes) {
String str = new String(bytes);
System.out.println("Error: " + str);
}
}
public class Message {
private String payload;
// getter setter
}
#Service
public class GatewayServiceImpl implements GatewayService<Message> {
#Autowired
private Gateway gateway;
#Autowired
private GatewayContextManger<String, Object> gatewayContextManger;
#Override
public void sendMessage(final Message message) {
new Thread(new Runnable() {
#Override
public void run() {
gateway.viaTcp(message.getPayload());
}
}).start();
}
#Override
public void receiveMessage(final String response) {
new Thread(new Runnable() {
#Override
public void run() {
Message message = new Message();
message.setPayload(response);
Object obj = message;
//Object obj = gatewayContextManger.get(message.getPayload());
synchronized (message) {
obj.notify();
System.out.println("Message Received : "+message.getPayload());
}
}
}).start();
}
}
You have: clientConnectionFactory.setSingleUse(true); This means the connection will be closed after the request; leave it false (default) to keep the connection open.