Spring cloud Eureka server is NOT replicating each other, displaying warning - spring

I am using two Eureka server in spring cloud to replicate each other, when I open the page at http://localhost:8761, I saw this message:
RENEWALS ARE LESSER THAN THE THRESHOLD. THE SELF PRESERVATION MODE IS TURNED OFF.THIS MAY NOT PROTECT INSTANCE EXPIRY IN CASE OF NETWORK/OTHER PROBLEMS.
The eureka application.xml is this:
server:
port: ${server.instance.port:5678}
spring:
application:
name: nodeservice
sidecar:
port: ${nodeserver.instance.port:3000}
health-uri: http://localhost:${nodeserver.instance.port:3000}/health.json
eureka:
instance:
hostname: ${nodeserver.instance.name:localhost}
preferIpAddress: ${preferipaddress:false}
leaseRenewalIntervalInSeconds: 5 #default is 30, recommended to keep default
metadataMap:
instanceId: ${spring.application.name}:${spring.application.instance_id:${random.value}}
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/
So if I go to http://localhost:8761, I see all the services registered, but if I go to http://localhost:8762, I then see no micro-service registered.
Any idea why?

Eureka: register only the first success url. In your case the first success url is http://localhost:8761/eureka/ so it's not continue to register the next url http://localhost:8762/eureka/.
You can override that by:
Application.yml
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
additionalZones: http://localhost:8762/eureka
Your Application.java
#SpringBootApplication
#EnableEurekaClient
public class Application implements ApplicationContextAware {
#Value("${eureka.client.serviceUrl.additionalZones:}")
String additionalZones;
ConfigurableApplicationContext applicationContext;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public Map<String, EurekaClient> additionalEurekaClients(ApplicationInfoManager manager,
#Autowired(required = false) HealthCheckHandler healthCheckHandler) {
HashMap clients = new HashMap<>();
if(Text.isEmpty(additionalZones))
return clients;
String[] hosts = additionalZones.split(",");
for(int i=0; i < hosts.length; i++)
{
EurekaClient client = new CloudEurekaClient(manager, new SimpleEurekaClientConfig(hosts[i].trim(),"defaultZone"), null,
this.applicationContext);
client.registerHealthCheck(healthCheckHandler);
String clientName = "client_"+ (i+1);
clients.put(clientName, client);
}
return clients;
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = (ConfigurableApplicationContext) applicationContext;
}
#PreDestroy
public void unRegisterInAllConfiguredDiscovery() {
Map<String, EurekaClient> additionalEurekaClients = this.applicationContext.getBean("additionalEurekaClients", Map.class);
additionalEurekaClients.forEach((k, v) -> v.shutdown());
}
}
SimpleEurekaClient.java
package com.netflix.eureka;
import org.springframework.cloud.netflix.eureka.EurekaClientConfigBean;
import java.util.Arrays;
import java.util.List;
public class SimpleEurekaClientConfig extends EurekaClientConfigBean {
private String eurekaUrl;
private String zone;
private String region = "us-east-1";
public SimpleEurekaClientConfig(String eurekaUrl, String zone, String region) {
this.eurekaUrl = eurekaUrl;
this.zone = zone;
this.region = region;
}
public SimpleEurekaClientConfig(String eurekaUrl, String zone) {
this.eurekaUrl = eurekaUrl;
this.zone = zone;
}
#Override
public String getRegion() {
return region;
}
#Override
public String[] getAvailabilityZones(String s) {
return new String[] {zone};
}
#Override
public List<String> getEurekaServerServiceUrls(String s) {
return Arrays.asList(eurekaUrl);
}
#Override
public boolean shouldEnforceRegistrationAtInit() {
return true;
}
#Override
public boolean shouldRegisterWithEureka() {
return true;
}
}

It's not a XML you need rename it to "application.YML"
https://en.wikipedia.org/wiki/YAML

Related

What is idea of bindings in spring boot rabbitmq?

I need to bind several exchanges with several routing keys to one single queue and be able to send messages by exchange and routing key and receive it by listening to queue by queue-name.
my code:
#Configuration
#RequiredArgsConstructor
#EnableConfigurationProperties(ExchangeConfig.class)
public class RabbitConfig {
private final ExchangeConfig exchangeConfig;
#Bean
public List<Binding> bindings() {
List<Binding> bindings = new ArrayList<>();
exchangeConfig.getExchangesWithKeys()
.forEach(exchangeWithKeys -> exchangeWithKeys.getRoutingKeys()
.forEach(key -> {
Exchange exchange = ExchangeBuilder.directExchange(exchangeWithKeys.getExchange()).build();
Queue queue = QueueBuilder.durable(exchangeConfig.getLogsQueue()).build();
Binding binding = BindingBuilder.bind(queue).to(exchange)
.with(key).noargs();
bindings.add(binding);
}));
return bindings;
}
}
config:
spring:
rabbitmq:
host: localhost
port: 5672
rabbitmq:
exchanges-with-keys:
- exchange: exchange1
routing-keys: exchange1.live, exchange1.after
- exchange: exchange2
routing-keys: exchange2.live, exchange2.after
- exchange: exchange3
routing-keys: exchange3.live, exchange3.after
logs-queue: log-messages_q
props:
#Data
#Component
#ConfigurationProperties(prefix = "rabbitmq")
public class ExchangeConfig {
private String logsQueue;
private List<ExchangeWithKeys> exchangesWithKeys;
#Data
public static class ExchangeWithKeys {
private String exchange;
private List<String> routingKeys;
}
}
listener:
#Component
#Slf4j
#RequiredArgsConstructor
public class LogsListener {
private final LogMessageEventProcessor logMessageEventProcessor;
#RabbitListener(queues = "${rabbitmq.logs-queue}")
public void onLiveEvent(LogMessageEvent event) {
log.info("Received log event message [{}]", event.getBody());
logMessageEventProcessor.processLogMessageEvent(event);
}
}
test:
#SpringBootTest
#ContextConfiguration(initializers = LogsListenerTest.Initializer.class)
class LogsListenerTest {
#Autowired
private RabbitTemplate template;
#ClassRule
private static final RabbitMQContainer container = new RabbitMQContainer("rabbitmq:3.7.25-management-alpine")
.withExposedPorts(5672, 15672).withQueue("log-messages_q");
#BeforeAll
private static void startRabbit() {container.start();}
#AfterAll
private static void stopRabbit() {
container.stop();
}
#Test
public void test() {
template.convertAndSend("exchange1", "exchange1.live", new LogMessageEvent());
template.receiveAndConvert("log-messages_q");
}
public static class Initializer implements
ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(#NotNull ConfigurableApplicationContext configurableApplicationContext) {
val values = TestPropertyValues.of(
"spring.rabbitmq.host=" + container.getContainerIpAddress(),
"spring.rabbitmq.port=" + container.getMappedPort(5672)
);
values.applyTo(configurableApplicationContext);
}
}
}
Everything above does not working.
So where should i put these bindings to make it work? Thanks.
What version are you using? The use of List<Binding> has been replaced by Declarables.
See https://docs.spring.io/spring-amqp/docs/current/reference/html/#collection-declaration
The documentation is a bit out of date, the admin declareCollections property was removed in 2.2.

AssertionError: expected:<8089> but was:<-1>

My application is running in local, I am trying to do Spring Rest Controller testing.
It is running in 8089 port.
In application.yml
spring:
profiles:
active: sit
In application-sit.yml
server:
port: 8089
servlet:
context-path: /myapp
In My base test case:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = MyApplication.class)
#WebAppConfiguration
public abstract class AbstractTest {
protected MockMvc mvc;
#Autowired
WebApplicationContext webApplicationContext;
#Value("${server.port}")
int serverPort;
/* #LocalManagementPort
int randomManagementPort;*/
protected void setUp() {
mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
protected String mapToJson(Object obj) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(obj);
}
protected <T> T mapFromJson(String json, Class<T> clazz)
throws JsonParseException, JsonMappingException, IOException {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(json, clazz);
}
}
My Controller Test class:
public class OtpControllerTest extends AbstractTest {
#Override
#Before
public void setUp() {
super.setUp();
}
#Test
public void sendOtpTest() throws Exception {
String uri = "/sendOtp";
SendOTPRequestDTO otpRequest = new SendOTPRequestDTO();
otpRequest.setClientId("default2");
otpRequest.setTag("tag");
otpRequest.setMobileNumber("4444888888");
String inputJson = super.mapToJson(otpRequest);
MvcResult mvcResult = mvc.perform(MockMvcRequestBuilders.post(uri)
//.accept(MediaType.APPLICATION_JSON_VALUE)).andReturn()
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content(inputJson)).andReturn();
int status = mvcResult.getResponse().getStatus();
String content = mvcResult.getResponse().getContentAsString();
assertEquals(8089,serverPort);
assertEquals(200, status);
}
}
I am getting output like this:
java.lang.AssertionError: expected:<8089> but was:<-1>
I gone through the all similar issues and tried even no result.
I am fallowing this source:
test.htmSpring Boot - Rest Controller Unit Test

Spring-boot: Beans are null during unit/integration test

I am new to sprint-boot. I have a spring-boot application which is working fine in it's regular path. Now as I am trying to write unit/integration tests, I find that my beans are null.
I appreciate any help on understanding why are they null and how to fix it. It seems that it is not able to pick up properties from the yml at all.Please let me know if any more clarification is required.
To clarify the structure:
The main class:
#SpringBootApplication
#EnableConfigurationProperties(ApplicationConfiguration.class)
public class Application {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(Application.class, args);
}
}
The properties file (src/main/java/resources/application.yml)
http:
url:
protocol: http
baseUrl: ${CONNECTOR_BASE_URL}
connectorListUrl : connectors
The configuration class that is using the above properties (ApplicationConfiguration.java) is :
#ConfigurationProperties(prefix = "http.url")
#Validated
#Data
public class ApplicationConfiguration {
private String protocol;
private String baseUrl;
private String connectorListUrl;
}
Now, the simplified version of the class(ContinuousMonitorServiceTask.java that I am trying to write my test on, looks like :
#Component
#Slf4j
public class ContinuousMonitorServiceTask extends TimerTask {
#Autowired MonitorHttpClient httpClient;
#Autowired ApplicationConfiguration config;
#PostConstruct
public void setUp() {
connectorListUrl =
config.getProtocol() + "://" + config.getBaseUrl() + "/" + config.getConnectorListUrl();
connectorListHeaderParams.clear();
connectorListHeaderParams.put("Accept", "application/json");
connectorListHeaderParams.put("Content-Type", "application/json");
connectorListGetRequest = new HttpGet(connectorListUrl);
httpClient.setHeader(connectorListGetRequest, connectorListHeaderParams);
}
public void fetchList() {
try {
response = httpClient.callApi("Get Connector List", connectorListGetRequest);
log.info(response.toString());
connectorListResponseHandler(response);
} catch (Exception e) {
log.error(e.getMessage());
}
}
}
The above code is working fine when I am executing.
Now when I am writing test, I need to mock api calls and hence, I have used MOCK-SERVER and my testSimple1 test has passed which is a simple test to see if the mock server can start and return expected response. However, while debugging simpleTest2, I am seeing
monitorTask is null
appConfig is null
monitorTask is null
Although, I have src/test/resources/application.yml as:
http:
url:
protocol: http
baseUrl: 127.0.0.1:8080
connectorListUrl : connectors
My guess is that appConfig is not able to pick up the properties from application.yml during test and hence everything is null.However, I am not 100% sure about what is happening in real time.
Here is how my test class looks like (Kind of dirty code, but I am putting it in it's current state to show what I have tried so far):
//#RunWith(MockitoJUnitRunner.class)
//#TestPropertySource(locations="classpath:application.yml")
//#RunWith(SpringJUnit4ClassRunner.class)
//#SpringApplicationConfiguration(ApplicationConfiguration.class)
#RunWith(SpringRunner.class)
#SpringBootTest(classes = ApplicationConfiguration.class)
//#EnableConfigurationProperties(ApplicationConfiguration.class)
public class ContinousMonitorTest {
private MockMvc mockMvc;
#Mock private MonitorHttpClient httpClient;
#Mock private ApplicationConfiguration appConfig;
#InjectMocks
//#MockBean
//#Autowired
private ContinuousMonitorServiceTask monitorTask;
TestRestTemplate restTemplate = new TestRestTemplate();
HttpHeaders headers = new HttpHeaders();
private static ClientAndServer mockServer;
#BeforeClass
public static void startServer() {
mockServer = startClientAndServer(8080);
}
#AfterClass
public static void stopServer() {
mockServer.stop();
}
private void createExpectationForInvalidAuth() {
new MockServerClient("127.0.0.1", 8080)
.when(
request()
.withMethod("GET")
.withPath("/validate")
.withHeader("\"Content-type\", \"application/json\""),
//.withBody(exact("{username: 'foo', password: 'bar'}")),
exactly(1))
.respond(
response()
.withStatusCode(401)
.withHeaders(
new Header("Content-Type", "application/json; charset=utf-8"),
new Header("Cache-Control", "public, max-age=86400"))
.withBody("{ message: 'incorrect username and password combination' }")
.withDelay(TimeUnit.SECONDS,1)
);
}
private GenericResponse hitTheServerWithGETRequest() {
String url = "http://127.0.0.1:8080/validate";
HttpClient client = HttpClientBuilder.create().build();
HttpGet post = new HttpGet(url);
post.setHeader("Content-type", "application/json");
GenericResponse response=null;
try {
StringEntity stringEntity = new StringEntity("{username: 'foo', password: 'bar'}");
post.getRequestLine();
// post.setEntity(stringEntity);
response=client.execute(post, new GenericResponseHandler());
} catch (Exception e) {
throw new RuntimeException(e);
}
return response;
}
#Test
public void testSimple1() throws Exception{
createExpectationForInvalidAuth();
GenericResponse response = hitTheServerWithGETRequest();
System.out.println("response customed : " + response.getResponse());
assertEquals(401, response.getStatusCd());
monitorTask.fetchConnectorList();
}
#Test
public void testSimple2() throws Exception{
monitorTask.fetchConnectorList();
}
as #second suggested above, I made a change in the testSimple2 test to look like and that resolved the above mentioned problem.
#Test
public void testSimple2() throws Exception{
mockMvc = MockMvcBuilders.standaloneSetup(monitorTask).build();
Mockito.when(appConfig.getProtocol()).thenReturn("http");
Mockito.when(appConfig.getBaseUrl()).thenReturn("127.0.0.1:8080");
Mockito.when(appConfig.getConnectorListUrl()).thenReturn("validate");
Mockito.when(httpClient.callApi(Mockito.any(), Mockito.any())).thenCallRealMethod();
monitorTask.setUp();
monitorTask.fetchConnectorList();
}
Alternatively, could have done:
#Before
public void init()
{
MockitoAnnotations.initMocks(this);
}

spring boot can not get configuration from application.yml

My spring boot application can not get configuration parameters from application.yml file. My main class as following:
#SpringBootApplication(scanBasePackages={"com.test"})
public class Main {
#Bean
public Validator validator(){
return new org.springframework.validation.beanvalidation.CustomValidatorBean();
}
public static void main(String[] args) throws IOException {
new SpringApplicationBuilder(Main.class)
.properties("application.yml")
.build()
.run(args);
}
}
My controller class as following:
#RestController
#RequestMapping("/test_traffic")
#Component
public class AnycastTrafficController {
#Autowired
TestService testService;
#GetMapping("/test")
public Object component() {
return testService.getTraffic();
}
}
My Service class as following:
#Service
public class TestService {
#Autowired
TestDao testDao;
public Object getTraffic() {
testDao.getTraff();
}
}
My Dao class as following:
#Component
public class TestDao {
#Autowired
MyDBConfig mydbConfig;
public DB getMyDBConfig () {
DB db = new DB(mydbConfig.id, mydbConfig.key);
return db;
}
}
My Config class as following:
#Configuration
#EnableConfigurationProperties
#ConfigurationProperties(prefix = "mydb")
public class MyDBConfig {
public String id;
public String key;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
}
My application.yml (which located at /src/main/resources)as following:
server:
port: 8003
context-path: /
logging:
level:
ROOT: INFO
org.springframework: INFO
org.springframework.data: INFO
com.alibaba: INFO
file: log/
docserver:
accessKeyId: 1111
accessKeySecret: 2222
---
spring:
profiles: dev
application:
name: test-application
mydb:
id: 1111111
key: 2222222
But when I started the Main class and request the url, it threw exception as following:
the id should not be empty.
that mean my Configuration class didn't get the configure data from yml file, so where I did wrong please. p.s(but the server port 8003 could be found by application). Thanks!
Your application.yml contains an invalid property option.
Instead of
spring:
profiles: dev
you should use
spring:
profiles:
active: dev
After correcting this this, the configuration processor should work properly.

Zuul Implementing Multiple ZuulFallbackProvider for multiple zuul routes

How can i implement multiple zuulFallbackProvider for multiple zuul routing.
I cant see an answer how to do it using a properties only other than exposing a restcontroller and implement a method with a hystrixcommand.
Can i make each of my service with its own zuulFallBackProvider bean?
application.yml
server:
port: 8080
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 20000
ribbon:
ReadTimeout: 20000
ConnectTimeout: 20000
zuul:
prefix: /api
ignoredServices: '*'
host:
connect-timeout-millis: 20000
socket-timeout-millis: 20000
routes:
kicks-service:
path: /kicks/**
serviceId: kicks-service
stripPrefix: false
sensitiveHeaders:
kicks-inventory:
path: /inventory/**
serviceId: kicks-inventory
stripPrefix: false
sensitiveHeaders:
This is my sample app
#SpringBootApplication
#EnableDiscoveryClient
#EnableZuulProxy
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
#Bean
public Prefilter prefilter(){
return new Prefilter();
}
#Bean
public ZuulFallbackProvider zuulFallbackProvider() {
return new ZuulFallbackProvider() {
#Override
public String getRoute() {
return "kicks-inventory";
}
#Override
public ClientHttpResponse fallbackResponse() {
return new ClientHttpResponse() {
#Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.OK;
}
#Override
public int getRawStatusCode() throws IOException {
return 200;
}
#Override
public String getStatusText() throws IOException {
return "OK";
}
#Override
public void close() {
}
#Override
public InputStream getBody() throws IOException {
return new ByteArrayInputStream("fallback".getBytes());
}
#Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
}
};
}
};
}
}
Each route will need a separate bean. They should return different route for getRoute method.
Please check this- http://tachniki.blogspot.in/2017/02/generic-ZuulFallbackProvider.html. Hope it will make it slightly easier.
You can have a default fallback provider for all routes, otherwise you need a fallback provider per route.
If you would like to provide a default fallback for all routes than
you can create a bean of type FallbackProvider and have the
getRoute method return * or null.
http://cloud.spring.io/spring-cloud-netflix/multi/multi__router_and_filter_zuul.html#hystrix-fallbacks-for-routes

Resources