I am attempting to create a TCP client to connect to a remote tcp server and wait to receive messages. So far I have the following code:
#EnableIntegration
#IntegrationComponentScan
#Configuration
public class TcpClientConfig {
#Bean
public TcpInboundGateway tcpInbound(AbstractClientConnectionFactory connectionFactory) {
TcpInboundGateway gate = new TcpInboundGateway();
gate.setConnectionFactory(connectionFactory);
gate.setClientMode(false);
gate.setRequestChannel(fromTcp());
return gate;
}
#Bean
public MessageChannel fromTcp() {
return new DirectChannel();
}
#MessageEndpoint
public static class Echo {
#Transformer(inputChannel = "fromTcp", outputChannel = "serviceChannel")
public String convert(byte[] bytes) {
return new String(bytes);
}
}
#ServiceActivator(inputChannel = "serviceChannel")
public void messageToService(String in) {
System.out.println(in);
}
#Bean
public EndOfLineSerializer endOfLineSerializer() {
return new EndOfLineSerializer();
}
#Bean
public AbstractClientConnectionFactory clientConnectionFactory() {
TcpNetClientConnectionFactory tcpNetServerConnectionFactory = new TcpNetClientConnectionFactory("192.XXX.XXX.XX", 4321);
tcpNetServerConnectionFactory.setSingleUse(false);
tcpNetServerConnectionFactory.setSoTimeout(300000);
tcpNetServerConnectionFactory.setDeserializer(endOfLineSerializer());
tcpNetServerConnectionFactory.setSerializer(endOfLineSerializer());
tcpNetServerConnectionFactory.setMapper(new TimeoutMapper());
return tcpNetServerConnectionFactory;
}
}
It starts up and connects to the remote server. However, I am not receiving any data in my serviceActivator method messageToService. To assure that data exists, I can successfully connect to my remote tcp server using telnet
telnet 192.XXX.XXX.XX 4321
Trying 192.XXX.XXX.XX...
Connected to 192.XXX.XXX.XX.
Escape character is '^]'.
Hello World
I have confirmed nothing is hitting my EndOfLineSerializer. What is wrong with my TCP client?
Bonus: Let's assume the hostname and port are determined by querying an API. How would I tell the TcpNetClientConnectionFactory to wait to try to connect until I have the correct data for the port?
Debug output:
main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2018-11-22 23:00:46.182 DEBUG 35953 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Autodetecting user-defined JMX MBeans
2018-11-22 23:00:46.194 DEBUG 35953 --- [ main] .s.i.c.GlobalChannelInterceptorProcessor : No global channel interceptors.
2018-11-22 23:00:46.198 DEBUG 35953 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase -2147483648
2018-11-22 23:00:46.198 INFO 35953 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Adding {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel
2018-11-22 23:00:46.198 INFO 35953 --- [ main] o.s.i.channel.PublishSubscribeChannel : Channel 'application.errorChannel' has 1 subscriber(s).
2018-11-22 23:00:46.198 INFO 35953 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started _org.springframework.integration.errorLogger
2018-11-22 23:00:46.198 DEBUG 35953 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Successfully started bean '_org.springframework.integration.errorLogger'
2018-11-22 23:00:46.198 INFO 35953 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Adding {service-activator:tcpClientConfig.messageToService.serviceActivator} as a subscriber to the 'serviceChannel' channel
2018-11-22 23:00:46.198 INFO 35953 --- [ main] o.s.integration.channel.DirectChannel : Channel 'application.serviceChannel' has 1 subscriber(s).
2018-11-22 23:00:46.198 INFO 35953 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started tcpClientConfig.messageToService.serviceActivator
2018-11-22 23:00:46.198 DEBUG 35953 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Successfully started bean 'tcpClientConfig.messageToService.serviceActivator'
2018-11-22 23:00:46.198 INFO 35953 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Adding {transformer:tcpClientConfig.Echo.convert.transformer} as a subscriber to the 'toTcp' channel
2018-11-22 23:00:46.198 INFO 35953 --- [ main] o.s.integration.channel.DirectChannel : Channel 'application.toTcp' has 1 subscriber(s).
2018-11-22 23:00:46.198 INFO 35953 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started tcpClientConfig.Echo.convert.transformer
2018-11-22 23:00:46.198 DEBUG 35953 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Successfully started bean 'tcpClientConfig.Echo.convert.transformer'
2018-11-22 23:00:46.198 DEBUG 35953 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase 0
2018-11-22 23:00:46.199 INFO 35953 --- [ main] .s.i.i.t.c.TcpNetClientConnectionFactory : started clientConnectionFactory, host=192.XXX.XXX.90, port=4321
2018-11-22 23:00:46.199 DEBUG 35953 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Successfully started bean 'clientConnectionFactory'
2018-11-22 23:00:46.199 INFO 35953 --- [ main] .s.i.i.t.c.TcpNetClientConnectionFactory : started clientConnectionFactory, host=192.XXX.XXX.90, port=4321
2018-11-22 23:00:46.199 INFO 35953 --- [ main] o.s.i.ip.tcp.TcpInboundGateway : started tcpInbound
2018-11-22 23:00:46.199 DEBUG 35953 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Successfully started bean 'tcpInbound'
When using a client connection factory with an inbound endpoint there is no stimulus to open a connection (client factories are normally used for outbound operations and the connection is established when the first message is sent).
When used in this mode, you need setClientMode(true). This starts a task that opens (and monitors) an outbound connection.
See the documentation
Normally, inbound adapters use a type="server" connection factory, which listens for incoming connection requests. In some cases, you may want to establish the connection in reverse, such that the inbound adapter connects to an external server and then waits for inbound messages on that connection.
This topology is supported by setting client-mode="true" on the inbound adapter. In this case, the connection factory must be of type client and must have single-use set to false.
Two additional attributes support this mechanism. retry-interval specifies (in milliseconds) how often the framework attempts to reconnect after a connection failure. scheduler supplies a TaskScheduler to schedule the connection attempts and to test that the connection is still active.
(The framework provides a default scheduler).
For your Bonus question, you would need to find the host/port before creating the application context; or create the connection factory and gateway dynamically after you have the information.
Related
I have a spring boot app deployed to google cloud (via automatic github build).
Unfortunately my subscriber to pub/sub is being removed immediately after deployment :( Does anyone know reason for that?
Removing {service-activator:investobotAPIs.messageReceiver.serviceActivator} as a subscriber to the 'inputMessageChannel' channel
I've created a topic in google pub/sub and a subscription:
I've added these methods:
#RestController
#EnableAsync
public class InvestobotAPIs {
...
// [START pubsub_spring_inbound_channel_adapter]
// Create a message channel for messages arriving from the subscription `sub-one`.
#Bean
public MessageChannel inputMessageChannel() {
return new PublishSubscribeChannel();
}
// Create an inbound channel adapter to listen to the subscription `sub-one` and send
// messages to the input message channel.
#Bean
public PubSubInboundChannelAdapter inboundChannelAdapter(
#Qualifier("inputMessageChannel") MessageChannel messageChannel,
PubSubTemplate pubSubTemplate) {
PubSubInboundChannelAdapter adapter =
new PubSubInboundChannelAdapter(pubSubTemplate, "fetch-gpw-sub");
adapter.setOutputChannel(messageChannel);
adapter.setAckMode(AckMode.MANUAL);
adapter.setPayloadType(String.class);
return adapter;
}
// Define what happens to the messages arriving in the message channel.
#ServiceActivator(inputChannel = "inputMessageChannel")
public void messageReceiver(
String payload,
#Header(GcpPubSubHeaders.ORIGINAL_MESSAGE) BasicAcknowledgeablePubsubMessage message) {
logger.info("Message arrived via an inbound channel adapter from fetch-gpw! Payload: " + payload);
message.ack();
}
// [END pubsub_spring_inbound_channel_adapter]
and this is my build.graddle:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web:2.5.5'
// get url and download files
implementation 'commons-io:commons-io:2.6'
implementation 'org.asynchttpclient:async-http-client:2.12.3'
// parse xls files
implementation 'org.apache.poi:poi:5.0.0'
implementation 'org.apache.poi:poi-ooxml:5.0.0'
// firebase messaging and db
implementation 'com.google.firebase:firebase-admin:8.1.0'
// subscribe pub/sub topic
implementation 'com.google.cloud:spring-cloud-gcp-starter-pubsub:2.0.4'
implementation 'com.google.cloud:spring-cloud-gcp-pubsub-stream-binder:2.0.4'
implementation 'com.google.cloud:spring-cloud-gcp-dependencies:2.0.4'
}
Unfortunately when it is deployed the logs show that just after deployment is gets removed:
2021-10-20 11:51:16.190 CEST2021-10-20 09:51:16.190 INFO 1 --- [ main] o.s.i.channel.PublishSubscribeChannel : Channel 'application.inputMessageChannel' has 1 subscriber(s).
Default
2021-10-20 11:51:16.190 CEST2021-10-20 09:51:16.190 INFO 1 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started bean 'investobotAPIs.messageReceiver.serviceActivator'
Default
2021-10-20 11:51:16.214 CEST2021-10-20 09:51:16.214 INFO 1 --- [ main] .g.c.s.p.i.i.PubSubInboundChannelAdapter : started bean 'inboundChannelAdapter'; defined in: 'class path resource [com/miloszdobrowolski/investobotbackend/InvestobotAPIs.class]'; from source: 'com.miloszdobrowolski.investobotbackend.InvestobotAPIs.inboundChannelAdapter(org.springframework.messaging.MessageChannel,com.google.cloud.spring.pubsub.core.PubSubTemplate)'
Default
2021-10-20 11:51:16.295 CEST2021-10-20 09:51:16.294 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
Default
2021-10-20 11:51:19.076 CEST2021-10-20 09:51:19.075 INFO 1 --- [ main] c.m.i.InvestobotBackendApplication : Started InvestobotBackendApplication in 14.475 seconds (JVM running for 19.248)
Info
2021-10-20 11:51:22.386 CESTCloud Runinvestobot-backend-autobuild {#type: type.googleapis.com/google.cloud.audit.AuditLog, resourceName: namespaces/our-shield-329019/services/investobot-backend-autobuild, response: {…}, serviceName: run.googleapis.com, status: {…}}
Debug
2021-10-20 11:51:54.075 CESTContainer Sandbox: Unsupported syscall setsockopt(0x16,0x29,0x31,0x3e96fd1f3a9c,0x4,0x0). It is very likely that you can safely ignore this message and that this is not the cause of any error you might be troubleshooting. Please, refer to https://gvisor.dev/c/linux/amd64/setsockopt for more information.
Debug
2021-10-20 11:51:54.075 CESTContainer Sandbox: Unsupported syscall setsockopt(0x16,0x29,0x12,0x3e96fd1f3a9c,0x4,0x0). It is very likely that you can safely ignore this message and that this is not the cause of any error you might be troubleshooting. Please, refer to https://gvisor.dev/c/linux/amd64/setsockopt for more information.
Default
2021-10-20 11:52:59.196 CEST2021-10-20 09:52:59.195 WARN 1 --- [ault-executor-0] i.g.n.s.i.n.u.internal.MacAddressUtil : Failed to find a usable hardware address from the network interfaces; using random bytes: d1:79:21:a2:71:29:47:49
Default
2021-10-20 11:53:01.010 CEST2021-10-20 09:53:01.010 INFO 1 --- [ionShutdownHook] .g.c.s.p.i.i.PubSubInboundChannelAdapter : stopped bean 'inboundChannelAdapter'; defined in: 'class path resource [com/miloszdobrowolski/investobotbackend/InvestobotAPIs.class]'; from source: 'com.miloszdobrowolski.investobotbackend.InvestobotAPIs.inboundChannelAdapter(org.springframework.messaging.MessageChannel,com.google.cloud.spring.pubsub.core.PubSubTemplate)'
Default
2021-10-20 11:53:01.010 CEST2021-10-20 09:53:01.010 INFO 1 --- [ionShutdownHook] o.s.i.endpoint.EventDrivenConsumer : Removing {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel
Default
2021-10-20 11:53:01.010 CEST2021-10-20 09:53:01.010 INFO 1 --- [ionShutdownHook] o.s.i.channel.PublishSubscribeChannel : Channel 'application.errorChannel' has 0 subscriber(s).
Default
2021-10-20 11:53:01.011 CEST2021-10-20 09:53:01.011 INFO 1 --- [ionShutdownHook] o.s.i.endpoint.EventDrivenConsumer : stopped bean '_org.springframework.integration.errorLogger'
Default
2021-10-20 11:53:01.011 CEST2021-10-20 09:53:01.011 INFO 1 --- [ionShutdownHook] o.s.i.endpoint.EventDrivenConsumer : Removing {service-activator:investobotAPIs.messageReceiver.serviceActivator} as a subscriber to the 'inputMessageChannel' channel
Default
2021-10-20 11:53:01.011 CEST2021-10-20 09:53:01.011 INFO 1 --- [ionShutdownHook] o.s.i.channel.PublishSubscribeChannel : Channel 'application.inputMessageChannel' has 0 subscriber(s).
Default
2021-10-20 11:53:01.011 CEST2021-10-20 09:53:01.011 INFO 1 --- [ionShutdownHook] o.s.i.endpoint.EventDrivenConsumer : stopped bean 'investobotAPIs.messageReceiver.serviceActivator'
I've tried to change dependencies in gradle from com.google.cloud to org.springframework.cloud (not sure how they differ)
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web:2.5.5'
// get url and download files
implementation 'commons-io:commons-io:2.6'
implementation 'org.asynchttpclient:async-http-client:2.12.3'
// parse xls files
implementation 'org.apache.poi:poi:5.0.0'
implementation 'org.apache.poi:poi-ooxml:5.0.0'
// firebase messaging and db
implementation 'com.google.firebase:firebase-admin:8.1.0'
// subscribe pub/sub topic
// implementation 'com.google.cloud:spring-cloud-gcp-starter-pubsub:2.0.4'
// implementation 'com.google.cloud:spring-cloud-gcp-pubsub-stream-binder:2.0.4'
// implementation 'com.google.cloud:spring-cloud-gcp-dependencies:2.0.4'
implementation 'org.springframework.cloud:spring-cloud-gcp-starter-bus-pubsub:1.2.8.RELEASE'
implementation 'org.springframework.cloud:spring-cloud-gcp-pubsub:1.2.8.RELEASE'
implementation 'org.springframework.cloud:spring-cloud-gcp-autoconfigure:1.2.8.RELEASE'
implementation 'org.springframework.integration:spring-integration-core:5.5.4'
}
But it only causes a different error during deployment:
ERROR: (gcloud.run.services.update) Cloud Run error: Container failed to start. Failed to start and then listen on the port defined by the PORT environment variable. Logs for this revision might contain more information.
In a spring boot project in configuration file there is a task executor whose code goes like this
#Bean(name = "asyncExec")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(50);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("CashFlowThread-");
executor.initialize();
return executor;
}
I am deploying an API which download from s3 bucket and create 4 pdf and store it in target folder . while the api is called console shows error that asyncExec is shutting down .
Stack trace for it shows
Initializing Spring DispatcherServlet 'dispatcherServlet'
2020-12-01 17:04:30.174 INFO 3680 --- [nio-5000-exec-2] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2020-12-01 17:04:30.179 INFO 3680 --- [nio-5000-exec-2] o.s.web.servlet.DispatcherServlet : Completed initialization in 5 ms
2020-12-01 17:04:30.185 INFO 3680 --- [nio-5000-exec-2] com.zaxxer.hikari.HikariDataSource : HikariPool-17 - Starting...
2020-12-01 17:04:35.767 INFO 3680 --- [nio-5000-exec-2] com.zaxxer.hikari.HikariDataSource : HikariPool-17 - Start completed.
File is created!
Successfully obtained bytes from an S3 object
2020-12-01 17:04:43.907 INFO 3680 --- [ Thread-174] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'asyncExec'
2020-12-01 17:04:43.907 INFO 3680 --- [ Thread-174] com.zaxxer.hikari.HikariDataSource : HikariPool-17 - Shutdown initiated...
In my spring cloud application I want configure turbine service for dashboard. Example below:
server:
port: 0
turbine:
amqp:
port: 8989
---
spring:
profiles: docker
rabbitmq:
host: rabbitmq
turbine:
clusterNameExpression: new String("default")
appConfig: card-statement
combineHostPort: true
eureka:
instance:
preferIpAddress: true
client:
serviceUrl:
defaultZone: http://discovery-service:8761/eureka/
server:
port: 8989
Starting turbine service I have no errors. Docker contained in compose is registered as rabbitmq. card-statement is a service with some #HystrixCommand(fallbackMethod = to be observed on dashboard...
2019-05-14 16:12:57.288 INFO 6 --- [ main] faultConfiguringBeanFactoryPostProcessor : No bean named 'errorChannel' has been explicitly defined. Therefore, a default PublishSubscribeChannel will be created.
2019-05-14 16:12:57.373 INFO 6 --- [ main] faultConfiguringBeanFactoryPostProcessor : No bean named 'taskScheduler' has been explicitly defined. Therefore, a default ThreadPoolTaskScheduler will be created.
2019-05-14 16:12:57.441 INFO 6 --- [ main] faultConfiguringBeanFactoryPostProcessor : No bean named 'integrationHeaderChannelRegistry' has been explicitly defined. Therefore, a default DefaultHeaderChannelRegistry will be created.
2019-05-14 16:12:58.494 INFO 6 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.integration.config.IntegrationManagementConfiguration' of type [org.springframework.integration.config.IntegrationManagementConfiguration$$EnhancerBySpringCGLIB$$1a0a1e3f] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2019-05-14 16:12:58.617 INFO 6 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration$IntegrationJmxConfiguration' of type [org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration$IntegrationJmxConfiguration$$EnhancerBySpringCGLIB$$f59c295f] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2019-05-14 16:12:58.704 INFO 6 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration' of type [org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration$$EnhancerBySpringCGLIB$$2e83d22c] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2019-05-14 16:12:58.961 INFO 6 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'mbeanServer' of type [com.sun.jmx.mbeanserver.JmxMBeanServer] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2019-05-14 16:12:59.122 INFO 6 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'integrationDisposableAutoCreatedBeans' of type [org.springframework.integration.config.annotation.Disposables] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2019-05-14 16:12:59.354 INFO 6 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration' of type [org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration$$EnhancerBySpringCGLIB$$cb32660d] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2019-05-14 16:13:01.701 WARN 6 --- [ main] io.undertow.websockets.jsr : UT026010: Buffer pool was not set on WebSocketDeploymentInfo, the default pool will be used
2019-05-14 16:13:01.889 INFO 6 --- [ main] io.undertow.servlet : Initializing Spring embedded WebApplicationContext
2019-05-14 16:13:01.889 INFO 6 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 15942 ms
2019-05-14 16:13:02.653 WARN 6 --- [ main] c.n.c.sources.URLConfigurationSource : No URLs will be polled as dynamic configuration sources.
2019-05-14 16:13:02.653 INFO 6 --- [ main] c.n.c.sources.URLConfigurationSource : To enable URLs as dynamic configuration sources, define System property archaius.configurationSource.additionalUrls or make config.properties available on classpath.
2019-05-14 16:13:02.745 INFO 6 --- [ main] c.netflix.config.DynamicPropertyFactory : DynamicPropertyFactory is initialized with configuration sources: com.netflix.config.ConcurrentCompositeConfiguration#70f59913
2019-05-14 16:13:08.116 WARN 6 --- [ main] c.n.c.sources.URLConfigurationSource : No URLs will be polled as dynamic configuration sources.
2019-05-14 16:13:08.116 INFO 6 --- [ main] c.n.c.sources.URLConfigurationSource : To enable URLs as dynamic configuration sources, define System property archaius.configurationSource.additionalUrls or make config.properties available on classpath.
2019-05-14 16:13:10.392 INFO 6 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2019-05-14 16:13:19.434 INFO 6 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 2 endpoint(s) beneath base path '/actuator'
2019-05-14 16:13:20.108 INFO 6 --- [ main] o.s.s.c.ThreadPoolTaskScheduler : Initializing ExecutorService 'taskScheduler'
2019-05-14 16:13:21.732 INFO 6 --- [ main] o.s.i.monitor.IntegrationMBeanExporter : Registering MessageChannel turbineStreamInput
2019-05-14 16:13:22.397 INFO 6 --- [ main] o.s.i.monitor.IntegrationMBeanExporter : Registering MessageChannel errorChannel
2019-05-14 16:13:22.608 INFO 6 --- [ main] o.s.i.monitor.IntegrationMBeanExporter : Registering MessageChannel nullChannel
2019-05-14 16:13:22.824 INFO 6 --- [ main] o.s.i.monitor.IntegrationMBeanExporter : Registering MessageHandler errorLogger
2019-05-14 16:13:23.068 INFO 6 --- [ main] o.s.i.monitor.IntegrationMBeanExporter : Registering MessageHandler hystrixStreamAggregator.sendToSubject.serviceActivator
2019-05-14 16:13:23.234 INFO 6 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Adding {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel
2019-05-14 16:13:23.235 INFO 6 --- [ main] o.s.i.channel.PublishSubscribeChannel : Channel 'turbine-1.errorChannel' has 1 subscriber(s).
2019-05-14 16:13:23.235 INFO 6 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started _org.springframework.integration.errorLogger
2019-05-14 16:13:23.236 INFO 6 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Adding {service-activator:hystrixStreamAggregator.sendToSubject.serviceActivator} as a subscriber to the 'turbineStreamInput' channel
2019-05-14 16:13:23.237 INFO 6 --- [ main] o.s.c.s.m.DirectWithAttributesChannel : Channel 'turbine-1.turbineStreamInput' has 1 subscriber(s).
2019-05-14 16:13:23.240 INFO 6 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started hystrixStreamAggregator.sendToSubject.serviceActivator
2019-05-14 16:13:23.342 INFO 6 --- [ main] o.s.c.n.eureka.InstanceInfoFactory : Setting initial instance status as: STARTING
2019-05-14 16:13:23.619 INFO 6 --- [ main] com.netflix.discovery.DiscoveryClient : Initializing Eureka in region us-east-1
2019-05-14 16:13:24.657 INFO 6 --- [ main] c.n.d.provider.DiscoveryJerseyProvider : Using JSON encoding codec LegacyJacksonJson
2019-05-14 16:13:24.657 INFO 6 --- [ main] c.n.d.provider.DiscoveryJerseyProvider : Using JSON decoding codec LegacyJacksonJson
2019-05-14 16:13:25.453 INFO 6 --- [ main] c.n.d.provider.DiscoveryJerseyProvider : Using XML encoding codec XStreamXml
2019-05-14 16:13:25.454 INFO 6 --- [ main] c.n.d.provider.DiscoveryJerseyProvider : Using XML decoding codec XStreamXml
2019-05-14 16:13:26.240 INFO 6 --- [ main] c.n.d.s.r.aws.ConfigClusterResolver : Resolving eureka endpoints via configuration
2019-05-14 16:13:26.352 INFO 6 --- [ main] com.netflix.discovery.DiscoveryClient : Disable delta property : false
2019-05-14 16:13:26.352 INFO 6 --- [ main] com.netflix.discovery.DiscoveryClient : Single vip registry refresh property : null
2019-05-14 16:13:26.352 INFO 6 --- [ main] com.netflix.discovery.DiscoveryClient : Force full registry fetch : false
2019-05-14 16:13:26.352 INFO 6 --- [ main] com.netflix.discovery.DiscoveryClient : Application is null : false
2019-05-14 16:13:26.352 INFO 6 --- [ main] com.netflix.discovery.DiscoveryClient : Registered Applications size is zero : true
2019-05-14 16:13:26.352 INFO 6 --- [ main] com.netflix.discovery.DiscoveryClient : Application version is -1: true
It seems some topics was created. Checking rabbit I do not see turbine service connection. Also trying to verify turbine.stream on dashboard I can see that stream is connected to dashboard, but no updates (card-statement service endpoints registered in hystrix was used). And last thing. I expected turbine is connected to RabbitMQ. I have not detected turbine connection to rabbit via admin console.
Issue
Is there any ideas how to fix turbine?
Turbine code:
#SpringBootApplication
#EnableTurbineStream
#EnableEurekaClient
#EnableDiscoveryClient
public class TurbineApplication {
public static void main(String[] args) {
SpringApplication.run(TurbineApplication.class, args);
}
}
I'm trying to save a basic document but despite connecting to mongodb successfully... It doesn't seem to want to save.
Spring logs
2018-10-03 00:17:25.998 INFO 10713 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
2018-10-03 00:17:26.049 INFO 10713 --- [ restartedMain] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2018-10-03 00:17:26.106 INFO 10713 --- [ctor-http-nio-1] r.ipc.netty.tcp.BlockingNettyContext : Started HttpServer on /0:0:0:0:0:0:0:0:8080
2018-10-03 00:17:26.106 INFO 10713 --- [ restartedMain] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port(s): 8080
2018-10-03 00:17:26.112 INFO 10713 --- [ restartedMain] c.l.s.ServiceLegalApplicationKt : Started ServiceLegalApplicationKt in 3.459 seconds (JVM running for 4.201)
2018-10-03 00:17:26.644 INFO 10713 --- [ntLoopGroup-2-2] org.mongodb.driver.connection : Opened connection [connectionId{localValue:3, serverValue:4}] to localhost:27017
application.properties
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=legal
spring.data.mongodb.repositories.type=reactive
spring.mongodb.embedded.version=4.0.2
basic interface and class
interface EventRepository: ReactiveMongoRepository<Event, String>
#Document
class Event(id: String, name: String)
trying a simple save function
#Service
class SomeService(val eventRepository: EventRepository)
{
fun save() = eventRepository.save(Event(UUID.randomUUID().toString(), "hey"))
}
Mono<Event> response = repository.save(Event(UUID.randomUUID().toString(), "hey"));
Changes in save method
fun save() = eventRepository.save(Event(UUID.randomUUID().toString(), "hey")).subscribe();
You have to invoke subscribe() method on Mono reference to see the logs or details.
To make you stream terminal with subscribe() operation and to get the Mono result at the same time - split into two separate operations:
Mono<String> myEvent = eventRepository.save(Event(UUID.randomUUID().toString(), "hey"));
myEvent.subscribe();
return myEvent;
You can also call .block() on the returned Reactive mono
Mono<Event> reactiveEvent = repository.save(); reactiveEvent.block()
Also read this
This is simple code in my Spring boot application:
package com.maxxton.SpringBootHelloWorld;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class SpringBootHelloWorldApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootHelloWorldApplication.class, args);
}
}
And a ApplicationListener class to listen to ApplicationEvent:
package com.maxxton.SpringBootHelloWorld;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
#Component
public class Test implements ApplicationListener {
#Override
public void onApplicationEvent(ApplicationEvent event) {
if (event.getClass().getSimpleName().equals("ApplicationReadyEvent")) {
System.out.println("-------------------------------------");
System.out.println(event.getClass().getSimpleName());
System.out.println("-------------------------------------");
}
}
}
build.gradle contains these dependencies:
dependencies {
compile("org.springframework.boot:spring-boot-starter-amqp")
compile("org.springframework.cloud:spring-cloud-starter-bus-amqp")
compile('org.springframework.boot:spring-boot-starter-web')
compile('org.springframework.boot:spring-boot-starter')
compile("org.springframework.cloud:spring-cloud-starter")
compile("org.springframework.cloud:spring-cloud-starter-security")
compile("org.springframework.cloud:spring-cloud-starter-eureka")
testCompile('org.springframework.boot:spring-boot-starter-test')
}
Now, when I run this spring boot application, I see this log printed twice:
[main] c.m.S.SpringBootHelloWorldApplication : Started SpringBootHelloWorldApplication in ... seconds (JVM running for ...)
Usually, this log get printed only once, but it get printed twice if I add these dependencies:
compile("org.springframework.boot:spring-boot-starter-amqp")
compile("org.springframework.cloud:spring-cloud-starter-bus-amqp")
This is complete log:
2017-11-17 15:44:07.372 INFO 5976 --- [ main] o.s.c.support.GenericApplicationContext : Refreshing org.springframework.context.support.GenericApplicationContext#31c7c281: startup date [Fri Nov 17 15:44:07 IST 2017]; root of context hierarchy
-------------------------------------
ApplicationReadyEvent
-------------------------------------
2017-11-17 15:44:07.403 INFO 5976 --- [ main] c.m.S.SpringBootHelloWorldApplication : Started SpringBootHelloWorldApplication in 1.19 seconds (JVM running for 10.231)
2017-11-17 15:44:09.483 WARN 5976 --- [ main] o.s.amqp.rabbit.core.RabbitAdmin : Failed to declare exchange: Exchange [name=springCloudBus, type=topic, durable=true, autoDelete=false, internal=false, arguments={}], continuing... org.springframework.amqp.AmqpConnectException: java.net.ConnectException: Connection refused: connect
2017-11-17 15:44:09.492 INFO 5976 --- [ main] o.s.integration.channel.DirectChannel : Channel 'a-bootiful-client.springCloudBusOutput' has 1 subscriber(s).
2017-11-17 15:44:09.493 INFO 5976 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase 0
2017-11-17 15:44:09.530 INFO 5976 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Adding {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel
2017-11-17 15:44:09.530 INFO 5976 --- [ main] o.s.i.channel.PublishSubscribeChannel : Channel 'a-bootiful-client.errorChannel' has 1 subscriber(s).
2017-11-17 15:44:09.530 INFO 5976 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started _org.springframework.integration.errorLogger
2017-11-17 15:44:09.530 INFO 5976 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase 2147482647
2017-11-17 15:44:09.539 INFO 5976 --- [ main] c.s.b.r.p.RabbitExchangeQueueProvisioner : declaring queue for inbound: springCloudBus.anonymous.kZ1vvxHaRfChKe1TncH-MQ, bound to: springCloudBus
2017-11-17 15:44:11.562 WARN 5976 --- [ main] o.s.amqp.rabbit.core.RabbitAdmin : Failed to declare exchange: Exchange [name=springCloudBus, type=topic, durable=true, autoDelete=false, internal=false, arguments={}], continuing... org.springframework.amqp.AmqpConnectException: java.net.ConnectException: Connection refused: connect
2017-11-17 15:44:13.587 WARN 5976 --- [ main] o.s.amqp.rabbit.core.RabbitAdmin : Failed to declare queue: Queue [name=springCloudBus.anonymous.kZ1vvxHaRfChKe1TncH-MQ, durable=false, autoDelete=true, exclusive=true, arguments={}], continuing... org.springframework.amqp.AmqpConnectException: java.net.ConnectException: Connection refused: connect
2017-11-17 15:44:15.611 WARN 5976 --- [ main] o.s.amqp.rabbit.core.RabbitAdmin : Failed to declare binding: Binding [destination=springCloudBus.anonymous.kZ1vvxHaRfChKe1TncH-MQ, exchange=springCloudBus, routingKey=#], continuing... org.springframework.amqp.AmqpConnectException: java.net.ConnectException: Connection refused: connect
2017-11-17 15:44:17.662 INFO 5976 --- [ main] o.s.i.a.i.AmqpInboundChannelAdapter : started inbound.springCloudBus.anonymous.kZ1vvxHaRfChKe1TncH-MQ
2017-11-17 15:44:17.662 INFO 5976 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Adding {message-handler:inbound.springCloudBus.default} as a subscriber to the 'bridge.springCloudBus' channel
2017-11-17 15:44:17.662 INFO 5976 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started inbound.springCloudBus.default
2017-11-17 15:44:17.663 INFO 5976 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase 2147483647
2017-11-17 15:44:17.714 INFO 5976 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
-------------------------------------
ApplicationReadyEvent
-------------------------------------
2017-11-17 15:44:17.717 INFO 5976 --- [ main] c.m.S.SpringBootHelloWorldApplication : Started SpringBootHelloWorldApplication in 20.131 seconds (JVM running for 20.545)
As you can see, ApplicationReadyEvent is happening twice.
Why is this happening?
Is there any way to avoid this?
spring-cloud-bus uses spring-cloud-stream which puts the binder in a separate boot child application context.
You should make your event listener aware of the application context it is running in. You can also use generics to select the event type you are interested in...
#Component
public class Test implements ApplicationListener<ApplicationReadyEvent>,
ApplicationContextAware {
private ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
#Override
public void onApplicationEvent(ApplicationReadyEvent event) {
if (event.getApplicationContext().equals(this.applicationContext)) {
System.out.println("-------------------------------------");
System.out.println(event.getClass().getSimpleName());
System.out.println("-------------------------------------");
}
}
}
Are u using multiple binders rabbitmq configuration in your application.yml/.xml ?
If it's a yes, then u can try to exclude RabbitAutoConfiguration.
#EnableDiscoveryClient
#EnableAutoConfiguration(exclude = {RabbitAutoConfiguration.class})
#SpringBootApplication
public class SpringBootHelloWorldApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootHelloWorldApplication.class, args);
}
}