Skip to content

Commit

Permalink
added native file system store for configuration server in developmen…
Browse files Browse the repository at this point in the history
…t mode, implemented circuit breaker pattern in position service
  • Loading branch information
ANIRBANSTIFLER committed Mar 30, 2021
1 parent 7f6f09c commit f61a52e
Show file tree
Hide file tree
Showing 9 changed files with 127 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@
@EnableConfigServer
public class ConfigurationServiceApplication {

private static String FP;

@Value("${spring.cloud.config.server.native.search-locations}")
public void setBaseLocation(String baseLocation) {
BL = baseLocation;
public void setFP(String filePath) {
FP = filePath;
}
static String BL;

public static void main(String[] args) {
SpringApplication.run(ConfigurationServiceApplication.class, args);
System.out.println(BL);
System.out.println(FP);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ server.port=8888

eureka.instance.prefer-ip-address=true

spring.cloud.loadbalancer.ribbon.enabled=false
spring.cloud.loadbalancer.ribbon.enabled=false

spring.cloud.config.server.native.search-locations=file:${PROJECT_BASE_DIR}/data/configuration-store
10 changes: 5 additions & 5 deletions data/configuration-store/polling-service-development.properties
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ spring.redis.port=6379
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka

ps.refresh.search.location=Stuttgart
ps.refresh.cron.expression=*/60 * * * * *
ps.cleanup.cron.expression=*/120 * * * * *
ps.cleanup.staleness.interval=30
ps.cleanup.ttl.eviction=30
ps.refresh.cron.expression=*/20 * * * * *
ps.cleanup.cron.expression=*/60 * * * * *
ps.cleanup.staleness.interval=10
ps.cleanup.ttl.eviction=10

car2go.base.url=http://192.168.0.109:3000
car2go.base.url=http://192.168.0.111:3000
car2go.vehicles.by.location.uri=/vehicles/{locationName}

#spring.redis.redisson.file=classpath:redisson.yaml
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,9 @@ poss.car-service.url=localhost:17080/car

poss.placement.infinite.end.limit=1000

eureka.instance.prefer-ip-address=true
eureka.instance.prefer-ip-address=true

poss.circuit-breaker.failure.threshold-percentage=30
poss.circuit-breaker.wait.duration.in-open-state=3000
poss.circuit-breaker.sliding-window.size=2
poss.circuit-breaker.timeout.duration=10
7 changes: 6 additions & 1 deletion data/configuration-store/position-service-staging.properties
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,9 @@ spring.sleuth.web.skipPattern=(^cleanup.*|.+favicon.*)

poss.placement.infinite.end.limit=1000

eureka.instance.prefer-ip-address=true
eureka.instance.prefer-ip-address=true

poss.circuit-breaker.failure.threshold-percentage=30
poss.circuit-breaker.wait.duration.in-open-state=3000
poss.circuit-breaker.sliding-window.size=3
poss.circuit-breaker.timeout.duration=3
4 changes: 4 additions & 0 deletions position-service/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@
<artifactId>jts-core</artifactId>
<version>${jts.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
package com.teenthofabud.codingchallenge.sharenow.position.configuration;

import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.github.resilience4j.timelimiter.TimeLimiterConfig;
import org.locationtech.jts.geom.GeometryFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JCircuitBreakerFactory;
import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JConfigBuilder;
import org.springframework.cloud.client.circuitbreaker.Customizer;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
Expand All @@ -9,6 +15,7 @@
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;

import java.time.Duration;
import java.util.Locale;

@Component
Expand Down Expand Up @@ -36,4 +43,25 @@ public GeometryFactory geometryFactory() {
}


@Bean
public Customizer<Resilience4JCircuitBreakerFactory> globalCircuitBreakerFactory(
@Value("${poss.circuit-breaker.failure.threshold-percentage}") float failureThresholdPercentage,
@Value("${poss.circuit-breaker.wait.duration.in-open-state}") long waitDurationInOpenStateInMillis,
@Value("${poss.circuit-breaker.sliding-window.size}") int slidingWindowSize,
@Value("${poss.circuit-breaker.timeout.duration}") long timeoutDurationInSeconds) {

CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
.failureRateThreshold(failureThresholdPercentage)
.waitDurationInOpenState(Duration.ofMillis(waitDurationInOpenStateInMillis))
.slidingWindowSize(slidingWindowSize)
.build();
TimeLimiterConfig timeLimiterConfig = TimeLimiterConfig.custom()
.timeoutDuration(Duration.ofSeconds(timeoutDurationInSeconds))
.build();
return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder(id)
.timeLimiterConfig(timeLimiterConfig)
.circuitBreakerConfig(circuitBreakerConfig)
.build());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,18 @@ public boolean isCarInsidePolygon(CarDetailsDTO carDTO, StrategicPolygonDetailed
if (coordinates != null && coordinates.size() < 3) {
throw new PositionServiceException("Invalid polygon", PositionErrorCode.UNEXPECTED_PARAMETER, new Object[] {"polygon vertex count < 3"});
} else {
List<Coordinate> polygonPointsList = polygonDTO.getGeometry().getExteriorRing().stream()
.map(lla -> new Coordinate(lla.getLongitude(), lla.getLatitude())).collect(Collectors.toList());
polygonPointsList.add(polygonPointsList.get(0)); // sanitizing polygon coordinates as per GeoJSOn specifications
Coordinate[] polygonPointsArray = polygonPointsList.toArray(new Coordinate[polygonPointsList.size()]);
Polygon strategicPolygon = geometryFactory.createPolygon(polygonPointsArray);
Coordinate carCoordinates = new Coordinate(carDTO.getPosition().getLongitude(), carDTO.getPosition().getLatitude());
Point carLocation = geometryFactory.createPoint(carCoordinates);
return strategicPolygon.contains(carLocation) || strategicPolygon.getBoundary().contains(carLocation);
if(carDTO.getPosition() != null) {
Coordinate carCoordinates = new Coordinate(carDTO.getPosition().getLongitude(), carDTO.getPosition().getLatitude());
List<Coordinate> polygonPointsList = polygonDTO.getGeometry().getExteriorRing().stream()
.map(lla -> new Coordinate(lla.getLongitude(), lla.getLatitude())).collect(Collectors.toList());
polygonPointsList.add(polygonPointsList.get(0)); // sanitizing polygon coordinates as per GeoJSOn specifications
Coordinate[] polygonPointsArray = polygonPointsList.toArray(new Coordinate[polygonPointsList.size()]);
Polygon strategicPolygon = geometryFactory.createPolygon(polygonPointsArray);
Point carLocation = geometryFactory.createPoint(carCoordinates);
return strategicPolygon.contains(carLocation) || strategicPolygon.getBoundary().contains(carLocation);
} else {
throw new PositionServiceException("Invalid car position", PositionErrorCode.UNEXPECTED_PARAMETER, new Object[] {"car position is not provided"});
}
}
} else {
throw new PositionServiceException("Invalid polygon", PositionErrorCode.INVALID_PARAMETER, new Object[] {"polygon coordinates"});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.teenthofabud.codingchallenge.sharenow.position.service.impl;

import com.ctc.wstx.sw.EncodingXmlWriter;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.teenthofabud.codingchallenge.sharenow.position.model.dto.car.CarDetailsDTO;
Expand All @@ -9,11 +8,13 @@
import com.teenthofabud.codingchallenge.sharenow.position.model.dto.polygon.StrategicPolygonDetailedDTO;
import com.teenthofabud.codingchallenge.sharenow.position.model.error.PositionErrorCode;
import com.teenthofabud.codingchallenge.sharenow.position.model.error.PositionServiceException;
import com.teenthofabud.codingchallenge.sharenow.position.model.vo.*;
import com.teenthofabud.codingchallenge.sharenow.position.model.vo.ErrorVO;
import com.teenthofabud.codingchallenge.sharenow.position.model.vo.car.Car2StrategicPolygonPositioningVO;
import com.teenthofabud.codingchallenge.sharenow.position.model.vo.car.CarMappedVO;
import com.teenthofabud.codingchallenge.sharenow.position.model.vo.car.PositionVO;
import com.teenthofabud.codingchallenge.sharenow.position.model.vo.polygon.*;
import com.teenthofabud.codingchallenge.sharenow.position.model.vo.polygon.GeoFeatureVO;
import com.teenthofabud.codingchallenge.sharenow.position.model.vo.polygon.StrategicPolygon2CarPositioningVO;
import com.teenthofabud.codingchallenge.sharenow.position.model.vo.polygon.StrategicPolygonMappedVO;
import com.teenthofabud.codingchallenge.sharenow.position.repository.CarServiceClient;
import com.teenthofabud.codingchallenge.sharenow.position.repository.PolygonServiceClient;
import com.teenthofabud.codingchallenge.sharenow.position.service.PlacementService;
Expand All @@ -22,6 +23,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.circuitbreaker.CircuitBreaker;
import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;

Expand All @@ -45,6 +48,13 @@ public class PositionServiceImpl implements PositionService {
@Autowired
private PolygonServiceClient polygonClient;

@Autowired
private CircuitBreakerFactory globalCircuitBreakerFactory;

private CircuitBreaker carServiceCircuitBreaker;

private CircuitBreaker polygonServiceCircuitBreaker;

private Converter<CarDetailsDTO, CarMappedVO> carDetailsDTO2VOConverter;

private Converter<StrategicPolygonDetailedDTO, StrategicPolygonMappedVO> polygonDetailsDTO2VOConverter;
Expand All @@ -55,6 +65,8 @@ public class PositionServiceImpl implements PositionService {

@PostConstruct
public void init() {
this.carServiceCircuitBreaker = globalCircuitBreakerFactory.create("car");
this.polygonServiceCircuitBreaker = globalCircuitBreakerFactory.create("polygon");
this.positionDTO2VOConverter = (dto) -> {
PositionVO vo = new PositionVO();
vo.setLatitude(dto.getLatitude());
Expand Down Expand Up @@ -108,14 +120,42 @@ private PositionServiceException parseFeignErrorResponse(FeignException e) {
return new PositionServiceException(e.getMessage(), PositionErrorCode.SYSTEM_ERROR, new Object[] {response});
}

private CarDetailsDTO getDefaultCarDetailsByVin(String vin) {
CarDetailsDTO carDetailsDTO = new CarDetailsDTO();
carDetailsDTO.setVin(vin);
return null;
}

private List<CarDetailsDTO> getDefaultCarDetailsList() {
return new ArrayList<CarDetailsDTO>();
}

private List<StrategicPolygonDetailedDTO> getDefaultStrategicPolygons() {
return new ArrayList<StrategicPolygonDetailedDTO>();
}

private StrategicPolygonDetailedDTO getDefaultStrategicPolygonDetailsById(String polygonId) {
StrategicPolygonDetailedDTO dto = new StrategicPolygonDetailedDTO();
dto.setId(polygonId);
return dto;
}

private List<StrategicPolygonDetailedDTO> getDefaultStrategicPolygonsAndTheirDetailsByName(String name) {
StrategicPolygonDetailedDTO dto = new StrategicPolygonDetailedDTO();
dto.setName(name);
return Arrays.asList(dto);
}

@Override
public Car2StrategicPolygonPositioningVO retrievePositionOfCarAndItsEnclosingPolygonByVin(String vin) throws PositionServiceException {
try {
Car2StrategicPolygonPositioningVO posVO = new Car2StrategicPolygonPositioningVO();
boolean found = false;
CarDetailsDTO carDetailsDTO = this.carClient.getCarDetailsByVin(vin);
CarDetailsDTO carDetailsDTO = this.carServiceCircuitBreaker.run(() -> this.carClient.getCarDetailsByVin(vin),
throwable -> this.getDefaultCarDetailsByVin(vin));
LOGGER.info("Retrieved car details for vin: {}", vin);
List<StrategicPolygonDetailedDTO> polygonDTOList = this.polygonClient.getAllPolygons();
List<StrategicPolygonDetailedDTO> polygonDTOList = this.polygonServiceCircuitBreaker.run(() -> this.polygonClient.getAllPolygons(),
throwable -> this.getDefaultStrategicPolygons());
if(polygonDTOList != null && !polygonDTOList.isEmpty()) {
LOGGER.info("Retrieved strategic polygons: {}", polygonDTOList.size());
for(StrategicPolygonDetailedDTO detailedPolygonDTO : polygonDTOList) {
Expand Down Expand Up @@ -147,9 +187,13 @@ public Car2StrategicPolygonPositioningVO retrievePositionOfCarAndItsEnclosingPol
public StrategicPolygon2CarPositioningVO retrievePositionsOfAllCarsWithinPolygonByPolygonId(String polygonId) throws PositionServiceException {
try {
StrategicPolygon2CarPositioningVO posVO = new StrategicPolygon2CarPositioningVO();
StrategicPolygonDetailedDTO polygonDTO = this.polygonClient.getPolygonDetailsById(polygonId);
//StrategicPolygonDetailedDTO polygonDTO = this.polygonClient.getPolygonDetailsById(polygonId);
StrategicPolygonDetailedDTO polygonDTO = this.polygonServiceCircuitBreaker.run(() -> this.polygonClient.getPolygonDetailsById(polygonId),
throwable -> this.getDefaultStrategicPolygonDetailsById(polygonId));
LOGGER.info("Retrieved strategic polygon details for id: {}", polygonId);
List<CarDetailsDTO> carDetailsDTOList = this.carClient.getAllCarsWithDetails();
//List<CarDetailsDTO> carDetailsDTOList = this.carClient.getAllCarsWithDetails();
List<CarDetailsDTO> carDetailsDTOList = this.carServiceCircuitBreaker.run(() -> this.carClient.getAllCarsWithDetails(),
throwable -> this.getDefaultCarDetailsList());
if(carDetailsDTOList != null && !carDetailsDTOList.isEmpty()) {
LOGGER.info("Retrieved cars: {}", carDetailsDTOList.size());
for(CarDetailsDTO carDetailsDTO : carDetailsDTOList) {
Expand Down Expand Up @@ -179,9 +223,13 @@ public StrategicPolygon2CarPositioningVO retrievePositionsOfAllCarsWithinPolygon
public Set<StrategicPolygon2CarPositioningVO> retrievePositionsOfAllCarsWithinPolygonByPolygonName(String name) throws PositionServiceException {
Set<StrategicPolygon2CarPositioningVO> posVOList = new TreeSet<>();
try {
List<StrategicPolygonDetailedDTO> polygonDTOList = this.polygonClient.getAllPolygonsByName(name);
//List<StrategicPolygonDetailedDTO> polygonDTOList = this.polygonClient.getAllPolygonsByName(name);
List<StrategicPolygonDetailedDTO> polygonDTOList = this.polygonServiceCircuitBreaker.run(() -> this.polygonClient.getAllPolygonsByName(name),
throwable -> this.getDefaultStrategicPolygonsAndTheirDetailsByName(name));
LOGGER.info("Retrieved strategic polygon details for name: {}", name);
List<CarDetailsDTO> carDetailsDTOList = this.carClient.getAllCarsWithDetails();
//List<CarDetailsDTO> carDetailsDTOList = this.carClient.getAllCarsWithDetails();
List<CarDetailsDTO> carDetailsDTOList = this.carServiceCircuitBreaker.run(() -> this.carClient.getAllCarsWithDetails(),
throwable -> this.getDefaultCarDetailsList());
if((carDetailsDTOList != null && !carDetailsDTOList.isEmpty()) &&
(polygonDTOList != null && !polygonDTOList.isEmpty())){
LOGGER.info("Retrieved cars: {}", carDetailsDTOList.size());
Expand All @@ -190,7 +238,7 @@ public Set<StrategicPolygon2CarPositioningVO> retrievePositionsOfAllCarsWithinPo
StrategicPolygon2CarPositioningVO posVO = new StrategicPolygon2CarPositioningVO();
List<CarDetailsDTO> auxCarDetailsDTOList = new ArrayList<>();
for(CarDetailsDTO carDetailsDTO : carDetailsDTOList) {
if(this.placementService.isCarInsidePolygon(carDetailsDTO, polygonDetailedDTO)) {
if (this.placementService.isCarInsidePolygon(carDetailsDTO, polygonDetailedDTO)) {
CarMappedVO carVO = this.carDetailsDTO2VOConverter.convert(carDetailsDTO);
posVO.addCar(carVO);
atleast1CarFound = true;
Expand Down

0 comments on commit f61a52e

Please sign in to comment.