Skip to content

Commit

Permalink
added base docker compose file, fixed cache eviction trigger in polli…
Browse files Browse the repository at this point in the history
…ng service, fixed compilation errosm in polling service, made vehicle entity type consistent for redis persistence to be shared acrioss two different projects, removed throwing exception from scheduled tasks, fixed cron timings for polling service for consistent results, implemented logic to determine vehicle staleness, moved functional interface implementations to init method of refresh service in polling service, implemented correct setting of expiration time for redis keys cleanup service of polling service, implemented end to end flow of vehicle service to get all vehicles and their details by their vin
  • Loading branch information
ANIRBANSTIFLER committed Mar 14, 2021
1 parent a7dc8d4 commit fd38b05
Show file tree
Hide file tree
Showing 51 changed files with 866 additions and 98 deletions.
Empty file added docker-compose.yml
Empty file.
5 changes: 5 additions & 0 deletions polling-service/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FROM adoptopenjdk:11-jre-hotspot-focal
MAINTAINER Anirban Das <anirbandas18@live.com>
RUN mkdip ~p /opt/sharenow-coding-challenge
COPY target/polling-app.jar /opt/sharenow-coding-challenge/polling-app.jar
CMD ["java","-jar","/opt/sharenow-coding-challenge/polling-app.jar"]
24 changes: 24 additions & 0 deletions polling-service/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,29 @@

<build>
<finalName>polling-app</finalName>
<plugins>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<version>1.4.13</version>
<executions>
<execution>
<id>default</id>
<goals>
<goal>build</goal>
<goal>push</goal>
</goals>
</execution>
</executions>
<configuration>
<repository>teenthofabud/sharenow-coding-challenge-${project.artifactId}</repository>
<tag>${project.version}</tag>
<buildArgs>
<JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
</buildArgs>
</configuration>
</plugin>
</plugins>
</build>

<dependencies>
Expand All @@ -44,4 +67,5 @@
</dependency>
</dependencies>


</project>
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableEurekaClient
@EnableScheduling
@EnableRedisRepositories
public class PollingServiceApplication {

public static void main(String[] args) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.teenthofabud.codingchallenge.sharenow.polling.cleanup.service;

import com.teenthofabud.codingchallenge.sharenow.polling.model.entity.VehicleEntity;

@FunctionalInterface
public interface VehicleStaleness {

public boolean isVehicleStale(VehicleEntity entity);

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

import com.teenthofabud.codingchallenge.sharenow.polling.PollingMonitor;
import com.teenthofabud.codingchallenge.sharenow.polling.cleanup.service.VehicleCleanupService;
import com.teenthofabud.codingchallenge.sharenow.polling.refresh.model.entity.VehicleEntity;
import com.teenthofabud.codingchallenge.sharenow.polling.refresh.repository.VehicleRepository;
import com.teenthofabud.codingchallenge.sharenow.polling.cleanup.service.VehicleStaleness;
import com.teenthofabud.codingchallenge.sharenow.polling.model.entity.VehicleEntity;
import com.teenthofabud.codingchallenge.sharenow.polling.repository.VehicleRepository;
import org.redisson.api.RKeys;
import org.redisson.api.RMapCache;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -13,6 +15,7 @@
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;


Expand All @@ -21,13 +24,11 @@ public class Car2GoVehicleCleanupServiceImpl implements VehicleCleanupService {

private static final Logger LOGGER = LoggerFactory.getLogger(Car2GoVehicleCleanupServiceImpl.class);

private static final long MIN_TTL_FOR_EVICTION = 1l;

@Value("${ps.cleanup.staleness.interval:60}")
private int stalenessIntervalInSeconds;

@Value("${ps.cleanup.stale.ttl:1}")
private long ttlSeconds;
@Value("${ps.cleanup.ttl.eviction:1}")
private long ttlEviction;

@Autowired
private RedissonClient redisson;
Expand All @@ -38,6 +39,22 @@ public class Car2GoVehicleCleanupServiceImpl implements VehicleCleanupService {
@Autowired
private PollingMonitor monitor;

private VehicleStaleness staleDetector;

@PostConstruct
private void init() {
this.staleDetector = (ve) -> {
boolean status = false;
if(ve != null) {
long now = System.currentTimeMillis();
long lastSeen = ve.getUpdatedAt().getTime();
long elapsed = now - lastSeen;
status = (elapsed/1000l) > stalenessIntervalInSeconds;
}
return status;
};
}


@Override
@Scheduled(cron = "${ps.cleanup.cron.expression:*/90 * * * *}")
Expand All @@ -48,24 +65,15 @@ public void clearStaleVehiclesForConfiguredCity() {
int count = 0;
LOGGER.info("Starting transaction for evicting stale vehicles by least recently updated policy");
for(VehicleEntity entity : itr) {
if(isVehicleStale(entity)) {
String vehicleId = String.valueOf(entity.getId());
keys.expire(vehicleId, MIN_TTL_FOR_EVICTION, TimeUnit.MILLISECONDS);
LOGGER.info("Preparing vehicle with id {} for eviction by assigning the lowest ttl", vehicleId);
if(this.staleDetector.isVehicleStale(entity)) {
String vehicleKey = entity.getCacheKey();
keys.expire(vehicleKey, ttlEviction, TimeUnit.SECONDS);
LOGGER.info("Preparing vehicle with id {} for eviction by assigning the lowest ttl", entity.getId());
count++;
}
}
LOGGER.info("Completed transaction for evicting {} stale vehicles", count);
}
}

private boolean isVehicleStale(VehicleEntity ve) {
boolean status = false;
long now = System.currentTimeMillis();
long lastSeen = ve.getUpdatedAt().getTime();
long elapsed = now - lastSeen;
status = (elapsed/1000l) > stalenessIntervalInSeconds;
return status;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.teenthofabud.codingchallenge.sharenow.polling.exception;

public enum PollingErrorCode {

REST_ERROR,
SCHEDULED_ERROR

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,24 @@
package com.teenthofabud.codingchallenge.sharenow.polling.exception;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class PollingServiceException extends RuntimeException {

private PollingErrorCode errorCode;
private String message;

public PollingServiceException(String message) {
super(message);
this.message = message;
}

public PollingServiceException(String message, PollingErrorCode errorCode) {
super(message);
this.message = message;
this.errorCode = errorCode;
}

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.teenthofabud.codingchallenge.sharenow.polling.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.teenthofabud.codingchallenge.sharenow.polling.refresh.model.dto.ErrorDTO;
import com.teenthofabud.codingchallenge.sharenow.polling.exception.PollingErrorCode;
import com.teenthofabud.codingchallenge.sharenow.polling.exception.PollingServiceException;
import com.teenthofabud.codingchallenge.sharenow.polling.model.dto.ErrorDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
Expand Down Expand Up @@ -36,6 +38,7 @@ public void handleError(ClientHttpResponse clientHttpResponse) throws IOExceptio
.series() == HttpStatus.Series.SERVER_ERROR) {
ErrorDTO err = om.readValue(clientHttpResponse.getBody(), ErrorDTO.class);
LOGGER.error("Unexpected server error: [{}={}]", clientHttpResponse.getRawStatusCode(), err.toString());
throw new PollingServiceException(err.toString(), PollingErrorCode.REST_ERROR);
} else if (clientHttpResponse.getStatusCode()
.series() == HttpStatus.Series.CLIENT_ERROR) {
ErrorDTO err = om.readValue(clientHttpResponse.getBody(), ErrorDTO.class);
Expand All @@ -44,6 +47,7 @@ public void handleError(ClientHttpResponse clientHttpResponse) throws IOExceptio
} else {
LOGGER.error("Unexpected client error: [{}={}]", clientHttpResponse.getRawStatusCode(), err.toString());
}
throw new PollingServiceException(err.toString(), PollingErrorCode.REST_ERROR);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.teenthofabud.codingchallenge.sharenow.polling.filter;

import com.teenthofabud.codingchallenge.sharenow.polling.exception.PollingErrorCode;
import com.teenthofabud.codingchallenge.sharenow.polling.exception.PollingServiceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.task.TaskSchedulerCustomizer;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

@Configuration
public class ScheduledServiceErrorHandler implements TaskSchedulerCustomizer {

private static final Logger LOGGER = LoggerFactory.getLogger(ScheduledServiceErrorHandler.class);

@Override
public void customize(ThreadPoolTaskScheduler taskScheduler) {
taskScheduler.setErrorHandler(t -> {
LOGGER.error("Error executing scheduled task: {}", t.getMessage());
t.printStackTrace();
});
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.teenthofabud.codingchallenge.sharenow.polling.refresh.model.dto;
package com.teenthofabud.codingchallenge.sharenow.polling.model.dto;


import lombok.Getter;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.teenthofabud.codingchallenge.sharenow.polling.refresh.model.dto;
package com.teenthofabud.codingchallenge.sharenow.polling.model.dto;

import lombok.Getter;
import lombok.Setter;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.teenthofabud.codingchallenge.sharenow.polling.refresh.model.dto;
package com.teenthofabud.codingchallenge.sharenow.polling.model.dto;

import lombok.Getter;
import lombok.Setter;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.teenthofabud.codingchallenge.sharenow.polling.refresh.model.entity;
package com.teenthofabud.codingchallenge.sharenow.polling.model.entity;

import lombok.Getter;
import lombok.Setter;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.teenthofabud.codingchallenge.sharenow.polling.refresh.model.entity;
package com.teenthofabud.codingchallenge.sharenow.polling.model.entity;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.TypeAlias;
import org.springframework.data.redis.core.RedisHash;
import org.springframework.data.redis.core.index.Indexed;

import java.io.Serializable;
import java.util.Date;
Expand All @@ -13,11 +15,13 @@
@Setter
@ToString
@RedisHash("Vehicle")
@TypeAlias("Vehicle")
public class VehicleEntity implements Serializable {

@Id
private int id;
private int locationId;
@Indexed
private String vin;
private String numberPlate;
private PositionEntity position;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
package com.teenthofabud.codingchallenge.sharenow.polling.refresh.configuration;

import io.lettuce.core.RedisClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
import org.springframework.stereotype.Component;

@Component
@EnableRedisRepositories
public class VehicleRefreshConfiguration {

@Autowired
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.teenthofabud.codingchallenge.sharenow.polling.refresh.converter;

import com.teenthofabud.codingchallenge.sharenow.polling.refresh.model.dto.PositionDTO;
import com.teenthofabud.codingchallenge.sharenow.polling.refresh.model.entity.PositionEntity;
import com.teenthofabud.codingchallenge.sharenow.polling.model.dto.PositionDTO;
import com.teenthofabud.codingchallenge.sharenow.polling.model.entity.PositionEntity;
import org.springframework.core.convert.converter.Converter;

@FunctionalInterface
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.teenthofabud.codingchallenge.sharenow.polling.refresh.converter;

import com.teenthofabud.codingchallenge.sharenow.polling.refresh.model.dto.VehicleDTO;
import com.teenthofabud.codingchallenge.sharenow.polling.refresh.model.entity.VehicleEntity;
import com.teenthofabud.codingchallenge.sharenow.polling.model.dto.VehicleDTO;
import com.teenthofabud.codingchallenge.sharenow.polling.model.entity.VehicleEntity;
import org.springframework.core.convert.converter.Converter;

@FunctionalInterface
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.teenthofabud.codingchallenge.sharenow.polling.refresh.service;

import com.teenthofabud.codingchallenge.sharenow.polling.refresh.model.dto.VehicleDTO;

import com.teenthofabud.codingchallenge.sharenow.polling.model.dto.VehicleDTO;

import java.util.List;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.teenthofabud.codingchallenge.sharenow.polling.refresh.service;

import com.teenthofabud.codingchallenge.sharenow.polling.refresh.model.entity.VehicleEntity;
import com.teenthofabud.codingchallenge.sharenow.polling.model.entity.VehicleEntity;

import java.util.List;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.teenthofabud.codingchallenge.sharenow.polling.refresh.service;

import com.teenthofabud.codingchallenge.sharenow.polling.refresh.model.dto.VehicleDTO;
import com.teenthofabud.codingchallenge.sharenow.polling.refresh.model.entity.VehicleEntity;
import com.teenthofabud.codingchallenge.sharenow.polling.model.dto.VehicleDTO;
import com.teenthofabud.codingchallenge.sharenow.polling.model.entity.VehicleEntity;

import java.util.List;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.teenthofabud.codingchallenge.sharenow.polling.refresh.service;

import com.teenthofabud.codingchallenge.sharenow.polling.refresh.model.dto.VehicleDTO;
import com.teenthofabud.codingchallenge.sharenow.polling.model.dto.VehicleDTO;
import org.springframework.stereotype.Service;

import java.util.List;
Expand Down
Loading

0 comments on commit fd38b05

Please sign in to comment.