We are using Eureka for micro service communication of our project on localhost it is working properly but on production it is giving error Unknown host exception.
We deployed the micro services and eureka server on aws ec2 instance but they are on different networks.
All the micro services and eureka server are built using springboot and also we are using docker for deployment.
Tried using discovery client and rest template also we have used eureka instance IP address to communicate but it is giving time exception
Eureka sever applicaition properties
spring.application.name=ems-eureka-server
server.port=8761
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
client properties
eureka.client.service-url.defaultZone=http://xx.xx.xx.xx:8761/eureka/
eureka.instance.preferIpAddress=true
Code snippet where we tried to communicate
try {
RestTemplate restTemplate = new RestTemplate();
List<ServiceInstance> instances = discoveryClient.getInstances(EurekaEndPointsConstants.EMS_EMPLOYEE_USER);
String url = instances.get(0).getUri() + "/api/templates/v1/school/" + vacancyDTO.getOrganizationId();
HashMap response = restTemplate.getForObject(url, HashMap.class);
Integer statusCode = (Integer) response.get("statusCode");
if(statusCode != HttpStatus.OK.value()) {
throw new CustomExceptions("Organization with this id not found!", HttpStatus.NOT_FOUND.value());
}
} catch (Exception e) {
log.error(e.getLocalizedMessage(), e);
throw new CustomExceptions(e.getLocalizedMessage(), HttpStatus.INTERNAL_SERVER_ERROR.value());
}
here are the micro services AKA clients on eureka server which are deployed
Related
I have 2 microservices + an Eureka Server in which they are registerd.
I made really everything I could think of, yet when I try to call the login service from the manager service, I always get "Connection timed out".
POST http://localhost:9903/login
{
"username":"adm4",
"password":"adm4adm4"
}
I have tried to work with Spring RestTemplate and WebClient and also Apache HttpClient.
All the times, the flow reaches the post method, and I get the same result.
I guess it must be some configuration issue.
I am working on localhost with all modules.
It really drives me crzay!
Please advise. I appreciate it.
The relevant info is as follows. Please tell me if you need more info.
First of all you can see that the services are registered and up:
Next the code:
Manager (calling) Service:
(I left inside all my previous attempts commented)
#PostMapping("/login")
public void login(#RequestBody LoginRequest loginRequest) throws Exception {
String url = getBaseUrl("bbsim-login-service") + "/api/auth/signin";
/* CloseableHttpClient httpclient = HttpClients.createDefault();
try {
HttpPost httpPost = new HttpPost(getBaseUrl("bbsim-login-service") + "/api/auth/signin");
List<NameValuePair> params = new ArrayList<>();
params.add(new BasicNameValuePair("username", loginRequest.getUsername()));
params.add(new BasicNameValuePair("password", loginRequest.getPassword()));
httpPost.setEntity(new UrlEncodedFormEntity(params));
CloseableHttpResponse response = httpclient.execute(httpPost);
System.out.println(response.getStatusLine().getStatusCode());
} finally {
httpclient.close();
}
*/
/* HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
// Connect timeout: time is in milliseconds
clientHttpRequestFactory.setConnectTimeout(30000);
// Read timeout: time is in milliseconds
clientHttpRequestFactory.setReadTimeout(30000);
RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);
HttpEntity<LoginRequest> request = new HttpEntity<>(loginRequest);
JwtResponse res = restTemplate.postForObject(url, request, JwtResponse.class);
System.out.println(res);
*/
localApiClient
.post()
.uri(url)
.body(Mono.just(loginRequest), LoginRequest.class)
.retrieve()
.bodyToMono(JwtResponse.class)
.block();
}
private String getBaseUrl(String serviceName) {
Application application = eurekaClient.getApplication(serviceName);
InstanceInfo instanceInfo = application.getInstances().get(0);
String hostname = instanceInfo.getHostName();
int port = instanceInfo.getPort();
return "http://" + hostname + ":" + port;
}
application.yml:
server.port: 9903
spring:
application.name: bbsim-manager-service
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_URI:http://localhost:8088/eureka}
registryFetchIntervalSeconds: 1
# register-with-eureka: true
# fetch-registry: true
instance:
leaseRenewalIntervalInSeconds: 1
If I understand well, the request does not reach the login service at all.
Login (called) service:
#PostMapping("/signin")
public ResponseEntity<?> authenticateUser(#Valid #RequestBody LoginRequest loginRequest) {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));
SecurityContextHolder.getContext().setAuthentication(authentication);
String jwt = jwtUtils.generateJwtToken(authentication);
UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
List<String> roles = userDetails.getAuthorities().stream()
.map(item -> item.getAuthority())
.collect(Collectors.toList());
return ResponseEntity.ok().body(new JwtResponse(jwt,
userDetails.getId(),
userDetails.getUsername(),
userDetails.getEmail(),
roles));
}
application.yml file:
server.port: 9902
spring:
application:
name: bbsim-login-service
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8088/eureka/
registryFetchIntervalSeconds: 1
instance:
leaseRenewalIntervalInSeconds: 1
I addition, I tried the following - giving me the same results:
curl -d "#data.json" -H "Content-Type: application/json" -X POST http://localhost:9903/login
where data.json has the body contents.
This will not be a complete answer but I hope it helps you with your issue.
I think your problem could be related with a mix of the different IP address of your machine.
First, I think Eureka is exposing your services like host.docker.internal, as indicated, the logical name that references the host machine through the different docker containers, for the reason explained in this SO question.
Basically, it seems that the docker software is updating your hosts file with entries for host.docker.internal and gateway.docker.internal and Eureka probably is taking that alias as the one for the machine IP that is being advertised. Please, see the accepted answer in the aforementioned question.
When you run Spring Boot normally the underlying server (Tomcat, Jetty, Undertow) will listen for connections in the 0.0.0.0 address, i.e., in all the network interfaces available, including localhost. This is what troubles me, because as indicated, the service should be accessible through all the IPs in the machine.
In any way, I think you can try several things to solve your issue.
Probably the best approach to solve the problem will be to configure the hostname of your Eureka server and/or your Eureka clients to a common one.
For example, you can configure your server and clients to be exposed as localhost.
For that purpose, you need to include the following configuration property in their respective config files:
eureka:
instance:
hostname: localhost
Looks like you are using Docker. You are trying to connect to localhost but other services are running in other container hence localhost won’t work. Would you please try 0.0.0.0 or host.docker.internal in your YAML file and see if that will work.
In other words you will need to edit following.
server.port: 9903
spring:
application.name: bbsim-manager-service
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_URI:http://host.docker.internal:8088/eureka}
registryFetchIntervalSeconds: 1
# register-with-eureka: true
# fetch-registry: true
instance:
leaseRenewalIntervalInSeconds: 1
or change EUREKA_URI env variable to reflect that. Also in your service YAML
server.port: 9902
spring:
application:
name: bbsim-login-service
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_URI:http://host.docker.internal:8088/eureka/}
registryFetchIntervalSeconds: 1
instance:
leaseRenewalIntervalInSeconds: 1
Hello I am new on spring integration
I checked examples for Spring Integration dynamic routing. Finally ı found it in here
Dynamic TCP Client
In here there were lines
#Component
#MessagingGateway(defaultRequestChannel = "toTcp.input")
public interface TcpClientGateway {
byte[] send(String data, #Header("host") String host, #Header("port") int port);
}
private MessageChannel createNewSubflow(Message<?> message) {
String host = (String) message.getHeaders().get("host");
Integer port = (Integer) message.getHeaders().get("port");
Assert.state(host != null && port != null, "host and/or port header missing");
String hostPort = host + port;
TcpNetClientConnectionFactory cf = new TcpNetClientConnectionFactory(host, port);
TcpSendingMessageHandler handler = new TcpSendingMessageHandler();
handler.setConnectionFactory(cf);
IntegrationFlow flow = f -> f.handle(handler);
IntegrationFlowContext.IntegrationFlowRegistration flowRegistration =
this.flowContext.registration(flow)
.addBean(cf)
.id(hostPort + ".flow")
.register();
MessageChannel inputChannel = flowRegistration.getInputChannel();
this.subFlows.put(hostPort, inputChannel);
return inputChannel;
}
but i changed it with
private MessageChannel createNewSubflow(Message<?> message) {
String host = (String) message.getHeaders().get("host");
Integer port = (Integer) message.getHeaders().get("port");
Assert.state(host != null && port != null, "host and/or port header missing");
String hostPort = host + port;
TcpNetClientConnectionFactory cf = new TcpNetClientConnectionFactory(host, port);
cf.setLeaveOpen(true);
//cf.setSingleUse(true);
ByteArrayCrLfSerializer byteArrayCrLfSerializer =new ByteArrayCrLfSerializer();
byteArrayCrLfSerializer.setMaxMessageSize(1048576);
cf.setSerializer(byteArrayCrLfSerializer);
cf.setDeserializer(byteArrayCrLfSerializer);
TcpOutboundGateway tcpOutboundGateway = new TcpOutboundGateway();
tcpOutboundGateway.setConnectionFactory(cf);
IntegrationFlow flow = f -> f.handle(tcpOutboundGateway);
IntegrationFlowContext.IntegrationFlowRegistration flowRegistration =
this.flowContext.registration(flow)
.addBean(cf)
.id(hostPort + ".flow")
.register();
MessageChannel inputChannel = flowRegistration.getInputChannel();
this.subFlows.put(hostPort, inputChannel);
return inputChannel;
}
to work with request/response architecture. It really works fine because it provides dynamic routing with out creating tcp clients by hand.
At this point i need some help to improve my scenario. My scenario is like that;
Client sends a message to Server and receive that message's response from server but then server needs to send arbitrary messages to that client (it is like GPS location update information). When server starts to send these messages to client generates error messages like below
ERROR 54816 --- [pool-2-thread-1] o.s.i.ip.tcp.TcpOutboundGateway : Cannot correlate response - no pending reply for ::58628:62fd67b6-af2d-42f1-9c4d-d232fbe9c8ca
I checked spring integration document and noticed that Gateways is working only with request/response so i learned that i should use adapters but i do not know how should i use adapters with dynamic tcp client.
here ı found similar topics and some responses but could not reach my goal or found example to combine solutions.
Spring Integration TCP
Spring integration TCP server push to client
You just need to register two flows; one for input; one for output - the problem is correlating the response for the reply, and routing the arbitrary messages to some place other than the gateway.
I updated the sample for this use case on this branch.
You can see the changes in the last commit on that branch; most of the changes were to simulate your server side.
On the client side, we simply register two flows and use a #ServiceActivator method to get the inbound messages; you can identify which server they come from via the connection id.
I am kind of new to Google Cloud Platform.
I have deployed my Spring REST Services.
I am able to call the REST services them from a browser.
These services needs to be accessed only by a Service Account, and the access needs to be secured by the API Private Key.
Is there any sample code to do this?
String resourceURL = "lucky-curve-175103.appspot.com/myService?input={s1}";
RestTemplate restTemplate = new RestTemplate();
String testValue = "098-98-0987";
CwResult cwResult = restTemplate.getForObject(resourceURL, CwResult.class, testValue );
System.out.println("Result " + cwResult.getResult());
This code works and I get the Result printed on the console.
How do I make this call using the service account and privatekey ?
The getting started of the spring cloud ribbon is very easy and simple, and it is using the rest template to communicate with backend servers.
But in our project we are more like to use okhttp to do the http request, does anyone can help?
You can take a look at the spring-cloud-square project which supplies integration with Square's OkHttpClient and Netflix Ribbon via Spring Cloud Netflix, on the Github. Let's see a test method in the OkHttpRibbonInterceptorTests.java class
#Test
#SneakyThrows
public void httpClientWorks() {
Request request = new Request.Builder()
// here you use a service id, or virtual hostname
// rather than an actual host:port, ribbon will
// resolve it
.url("http://" + SERVICE_ID + "/hello")
.build();
Response response = builder.build().newCall(request).execute();
Hello hello = new ObjectMapper().readValue(response.body().byteStream(), Hello.class);
assertThat("response was wrong", hello.getValue(), is(equalTo("hello okhttp")));
}
My application needs to fetch an XML file from the web, as follows:
#Bean
public HTTPMetadataProvider metadataProvider()
throws MetadataProviderException {
String metadataURL = "http://idp.ssocircle.com/idp-meta.xml";
final Timer backgroundTaskTimer = new Timer(true);
HTTPMetadataProvider provider =
new HTTPMetadataProvider(backgroundTaskTimer, httpClient(), metadataURL);
provider.setParserPool(parserPool());
return provider;
}
I'm working by using a filtered network, thus the app is unable to retrieve that file.
There is a way to setup an HTTP Proxy (e.g. myproxy.eu:8080) in Spring Boot?
Alternatively, I could retrieve the XML file by using the HTTPS protocol, but I should properly setup the metadata provider in order to support an encrypted connection... How?
This is not something you can configure in spring boot, HttpClient is not using java variables.
Therefor you need to set the proxy on the httpClient manually:
HostConfiguration hostConfig = new HostConfiguration();
hostConfig.setProxyHost(new ProxyHost("your.proxy.host", 8080));
httpClient.setHostConfiguration(hostConfig);