Skip to content

Commit

Permalink
Redis fix from PR #166 moved to 4.8 based code. (#170)
Browse files Browse the repository at this point in the history
  • Loading branch information
karthik-tarento authored Jan 27, 2023
1 parent 0a5e3fe commit 1e2bcae
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 119 deletions.
4 changes: 4 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,10 @@
<version>18.0.0</version>
</dependency>

<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>

</dependencies>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
package org.sunbird.assessment.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
Expand All @@ -17,9 +27,8 @@
import org.sunbird.core.exception.ApplicationLogicError;
import org.sunbird.core.logger.CbExtLogger;

import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

@Service
@SuppressWarnings("unchecked")
Expand All @@ -43,52 +52,62 @@ public class AssessmentServiceV2Impl implements AssessmentServiceV2 {
@Autowired
AssessmentRepository assessmentRepository;

public SBApiResponse readAssessment(String assessmentIdentifier, String token) throws Exception {
SBApiResponse response = new SBApiResponse();
try {
String userId = RequestInterceptor.fetchUserIdFromAccessToken(token);
if (userId != null) {
Map<String, Object> assessmentAllDetail = (Map<String, Object>) redisCacheMgr
.getCache(Constants.ASSESSMENT_ID + assessmentIdentifier);
boolean isSuccess = true;
if (ObjectUtils.isEmpty(assessmentAllDetail)) {
Map<String, Object> hierarcyReadApiResponse = getReadHierarchyApiResponse(assessmentIdentifier, token);
if (!Constants.OK.equalsIgnoreCase((String) hierarcyReadApiResponse.get(Constants.RESPONSE_CODE))) {
isSuccess = false;
} else {
assessmentAllDetail = (Map<String, Object>) ((Map<String, Object>) hierarcyReadApiResponse
.get(Constants.RESULT)).get(Constants.QUESTION_SET);
redisCacheMgr.putCache(Constants.ASSESSMENT_ID + assessmentIdentifier, assessmentAllDetail);
}
}
response = prepareAssessmentResponse(assessmentAllDetail, isSuccess);
redisCacheMgr.putCache(Constants.USER_ASSESS_REQ + token, response.getResult().get(Constants.QUESTION_SET));
if (assessmentAllDetail.get(Constants.DURATION) != null) {
boolean resp = assessmentRepository.addUserAssesmentStartTime(userId, Constants.ASSESSMENT_ID + assessmentIdentifier, new Timestamp(new Date().getTime()));
return response;
}
}
} catch (Exception e) {
logger.error(e);
throw new ApplicationLogicError("REQUEST_COULD_NOT_BE_PROCESSED", e);
}
return response;
}
public SBApiResponse readAssessment(String assessmentIdentifier, String token) throws Exception {
SBApiResponse response = new SBApiResponse();
try {
String userId = RequestInterceptor.fetchUserIdFromAccessToken(token);
if (userId != null) {
String strAssessmentAllDetail = redisCacheMgr.getCache(Constants.ASSESSMENT_ID + assessmentIdentifier);

Map<String, Object> assessmentAllDetail = mapper.readValue(strAssessmentAllDetail,
new TypeReference<Map<String, Object>>() {
});
boolean isSuccess = true;
if (ObjectUtils.isEmpty(assessmentAllDetail)) {
Map<String, Object> hierarcyReadApiResponse = getReadHierarchyApiResponse(assessmentIdentifier,
token);
if (!Constants.OK.equalsIgnoreCase((String) hierarcyReadApiResponse.get(Constants.RESPONSE_CODE))) {
isSuccess = false;
} else {
assessmentAllDetail = (Map<String, Object>) ((Map<String, Object>) hierarcyReadApiResponse
.get(Constants.RESULT)).get(Constants.QUESTION_SET);
redisCacheMgr.putCache(Constants.ASSESSMENT_ID + assessmentIdentifier, assessmentAllDetail);
}
}
response = prepareAssessmentResponse(assessmentAllDetail, isSuccess);
redisCacheMgr.putCache(Constants.USER_ASSESS_REQ + token,
response.getResult().get(Constants.QUESTION_SET));
if (assessmentAllDetail.get(Constants.DURATION) != null) {
boolean resp = assessmentRepository.addUserAssesmentStartTime(userId,
Constants.ASSESSMENT_ID + assessmentIdentifier, new Timestamp(new Date().getTime()));
return response;
}
}
} catch (Exception e) {
logger.error(e);
throw new ApplicationLogicError("REQUEST_COULD_NOT_BE_PROCESSED", e);
}
return response;
}

public SBApiResponse readQuestionList(Map<String, Object> requestBody, String authUserToken) throws Exception {
try {
List<String> identifierList = getQuestionIdList(requestBody);
List<Object> questionList = new ArrayList<>();
List<String> newIdentifierList = new ArrayList<>();
List<Object> map = redisCacheMgr.mget(identifierList);
int size = map.size();
for (int i = 0; i < map.size(); i++) {
if (ObjectUtils.isEmpty(map.get(i))) {
newIdentifierList.add(identifierList.get(i));
} else {
questionList.add(filterQuestionMapDetail((Map<String, Object>) map.get(i)));
}
}
List<String> strQuestionList = redisCacheMgr.mget(identifierList);

int size = strQuestionList.size();
for (int i = 0; i < size; i++) {
if (ObjectUtils.isEmpty(strQuestionList.get(i))) {
newIdentifierList.add(identifierList.get(i));
} else {
Map<String, Object> questionMap = mapper.readValue(strQuestionList.get(i),
new TypeReference<Map<String, Object>>() {
});
questionList.add(filterQuestionMapDetail(questionMap));
}
}
if (newIdentifierList.size() > 0) {
Map<String, Object> questionMapResponse = readQuestionDetails(newIdentifierList);
if (questionMapResponse != null && Constants.OK.equalsIgnoreCase((String) questionMapResponse.get(Constants.RESPONSE_CODE))) {
Expand Down Expand Up @@ -116,14 +135,13 @@ public SBApiResponse readQuestionList(Map<String, Object> requestBody, String au
public SBApiResponse submitAssessment(Map<String, Object> data, String authUserToken) throws Exception {
SBApiResponse outgoingResponse = new SBApiResponse();
String assessmentId = (String) data.get(Constants.IDENTIFIER);
Map<String, Object> assessmentHierarchy = (Map<String, Object>) redisCacheMgr
String strAssessmentHierarchy = redisCacheMgr
.getCache(Constants.ASSESSMENT_ID + assessmentId);
// logger.info("Submit Assessment: userId: " + userId + ", data: " +
// data.toString());
// Check User exists
// if (!userUtilService.validateUser(userId)) {
// throw new BadRequestException("Invalid UserId.");
// }

Map<String, Object> assessmentHierarchy = mapper.readValue(strAssessmentHierarchy,
new TypeReference<Map<String, Object>>() {
});

String userId = RequestInterceptor.fetchUserIdFromAccessToken(authUserToken);
if (userId != null) {
Date assessmentStartTime = assessmentRepository.fetchUserAssessmentStartTime(userId, Constants.ASSESSMENT_ID + assessmentId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,16 @@
import org.sunbird.core.exception.ApplicationLogicError;
import org.sunbird.core.logger.CbExtLogger;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

@Service
public class AssessmentUtilServiceV2Impl implements AssessmentUtilServiceV2 {

@Autowired
RedisCacheMgr redisCacheMgr;

ObjectMapper mapper = new ObjectMapper();

private CbExtLogger logger = new CbExtLogger(getClass().getName());

Expand Down Expand Up @@ -121,9 +126,9 @@ private Map<String, Object> getQumlAnswers(List<String> questions) throws Except
Map<String, Object> ret = new HashMap<>();
for (String questionId : questions) {
List<String> correctOption = new ArrayList<>();

Map<String, Object> question = (Map<String, Object>) redisCacheMgr
.getCache(Constants.QUESTION_ID + questionId);
String strQuestion = redisCacheMgr.getCache(Constants.QUESTION_ID + questionId);
Map<String, Object> question = mapper.readValue(strQuestion, new TypeReference<Map<String, Object>>() {
});
if (ObjectUtils.isEmpty(question)) {
logger.error(new Exception("Failed to get the answer for question: " + questionId));
// TODO - Need to handle this scenario.
Expand Down
56 changes: 35 additions & 21 deletions src/main/java/org/sunbird/cache/RedisCacheMgr.java
Original file line number Diff line number Diff line change
@@ -1,37 +1,54 @@
package org.sunbird.cache;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.sunbird.common.util.CbExtServerProperties;
import org.sunbird.common.util.Constants;
import org.sunbird.core.logger.CbExtLogger;

import com.fasterxml.jackson.databind.ObjectMapper;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

@Component
public class RedisCacheMgr {

private static final int cache_ttl = 84600;

@Autowired
private RedisTemplate<String, Object> redisTemplate;
private JedisPool jedisPool;

@Autowired
CbExtServerProperties cbExtServerProperties;

private CbExtLogger logger = new CbExtLogger(getClass().getName());

ObjectMapper objectMapper = new ObjectMapper();

public Jedis getJedis() {
try (Jedis jedis = jedisPool.getResource()) {
return jedis;
}
}

public void putCache(String key, Object object) {
try {
int ttl = cache_ttl;
if (!StringUtils.isEmpty(cbExtServerProperties.getRedisTimeout())) {
ttl = Integer.parseInt(cbExtServerProperties.getRedisTimeout());
}
redisTemplate.opsForValue().set(Constants.REDIS_COMMON_KEY + key, object);
redisTemplate.expire(Constants.REDIS_COMMON_KEY + key, ttl, TimeUnit.SECONDS);
String data = objectMapper.writeValueAsString(object);
getJedis().set(Constants.REDIS_COMMON_KEY + key, data);
getJedis().expire(Constants.REDIS_COMMON_KEY + key, ttl);
logger.info("Cache_key_value " + Constants.REDIS_COMMON_KEY + key + " is saved in redis");
} catch (Exception e) {
logger.error(e);
Expand All @@ -40,7 +57,7 @@ public void putCache(String key, Object object) {

public boolean deleteKeyByName(String key) {
try {
redisTemplate.delete(Constants.REDIS_COMMON_KEY + key);
getJedis().del(Constants.REDIS_COMMON_KEY + key);
logger.info("Cache_key_value " + Constants.REDIS_COMMON_KEY + key + " is deleted from redis");
return true;
} catch (Exception e) {
Expand All @@ -52,9 +69,9 @@ public boolean deleteKeyByName(String key) {
public boolean deleteAllCBExtKey() {
try {
String keyPattern = Constants.REDIS_COMMON_KEY + "*";
Set<String> keys = redisTemplate.keys(keyPattern);
Set<String> keys = getJedis().keys(keyPattern);
for (String key : keys) {
redisTemplate.delete(key);
getJedis().del(key);
}
logger.info("All Keys starts with " + Constants.REDIS_COMMON_KEY + " is deleted from redis");
return true;
Expand All @@ -64,51 +81,48 @@ public boolean deleteAllCBExtKey() {
}
}

public Object getCache(String key) {
public String getCache(String key) {
try {
return redisTemplate.opsForValue().get(Constants.REDIS_COMMON_KEY + key);
return getJedis().get(Constants.REDIS_COMMON_KEY + key);
} catch (Exception e) {
logger.error(e);
return null;
}
}

public List<Object> mget(List<String> fields) {
public List<String> mget(List<String> fields) {
try {
List<String> ls = new ArrayList<>();
String[] updatedKeys = new String[fields.size()];
for (int i = 0; i < fields.size(); i++) {
ls.add(Constants.REDIS_COMMON_KEY + Constants.QUESTION_ID + fields.get(i));
updatedKeys[i] = Constants.REDIS_COMMON_KEY + Constants.QUESTION_ID + fields.get(i);
}
Collection<String> questionIdList = ls;
return redisTemplate.opsForValue().multiGet(questionIdList);
getJedis().mget(updatedKeys);
} catch (Exception e) {
logger.error(e);
}
return null;
}

public Set<String> getAllKeyNames() {
Set<String> keys = null;
try {
String keyPattern = Constants.REDIS_COMMON_KEY + "*";
keys = redisTemplate.keys(keyPattern);
return getJedis().keys(keyPattern);
} catch (Exception e) {
logger.error(e);
return Collections.emptySet();
}
return keys;
}

public List<Map<String, Object>> getAllKeysAndValues() {
List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
try {
String keyPattern = Constants.REDIS_COMMON_KEY + "*";
Map<String, Object> res = new HashMap<>();
Set<String> keys = redisTemplate.keys(keyPattern);
Set<String> keys = getJedis().keys(keyPattern);
if (!keys.isEmpty()) {
for (String key : keys) {
Object entries;
entries = redisTemplate.opsForValue().get(key);
entries = getJedis().get(key);
res.put(key, entries);
}
result.add(res);
Expand Down
43 changes: 21 additions & 22 deletions src/main/java/org/sunbird/core/config/RedisConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.sunbird.common.util.CbExtServerProperties;

import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

@Configuration
@EnableCaching
public class RedisConfig {
Expand All @@ -19,24 +17,25 @@ public class RedisConfig {
CbExtServerProperties cbProperties;

@Bean
public JedisConnectionFactory jedisConnectionFactory() {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setHostName(cbProperties.getRedisHostName());
redisStandaloneConfiguration.setPort(Integer.parseInt(cbProperties.getRedisPort()));

JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration);
return jedisConnectionFactory;
public JedisPool jedisPool() {
final JedisPoolConfig poolConfig = buildPoolConfig();
JedisPool jedisPool = new JedisPool(poolConfig, cbProperties.getRedisHostName(),
Integer.parseInt(cbProperties.getRedisPort()));
return jedisPool;
}

@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(jedisConnectionFactory());
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new JdkSerializationRedisSerializer());
redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
redisTemplate.setEnableTransactionSupport(true);
redisTemplate.afterPropertiesSet();
return redisTemplate;
private JedisPoolConfig buildPoolConfig() {
final JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxIdle(128);
poolConfig.setMaxTotal(3000);
poolConfig.setMinIdle(100);
poolConfig.setTestOnBorrow(true);
poolConfig.setTestOnReturn(true);
poolConfig.setTestWhileIdle(true);
poolConfig.setMinEvictableIdleTimeMillis(120000);
poolConfig.setTimeBetweenEvictionRunsMillis(30000);
poolConfig.setNumTestsPerEvictionRun(3);
poolConfig.setBlockWhenExhausted(true);
return poolConfig;
}
}
Loading

0 comments on commit 1e2bcae

Please sign in to comment.