com.github.kaizen4j.redis.message.DefaultRedisMessageTemplate Maven / Gradle / Ivy
The newest version!
package com.github.kaizen4j.redis.message;
import com.github.kaizen4j.redis.connection.DelayMessage;
import com.github.kaizen4j.redis.connection.MessageConfig;
import com.github.kaizen4j.util.PrimitiveUtils;
import com.google.common.base.Preconditions;
import java.sql.Timestamp;
import java.time.Duration;
import java.util.Objects;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.BoundZSetOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.ZSetOperations;
/**
* @author liuguowen
*/
@SuppressWarnings("unchecked")
public class DefaultRedisMessageTemplate implements RedisMessageTemplate {
private static final Logger logger = LoggerFactory.getLogger(DefaultRedisMessageTemplate.class);
private RedisTemplate redisTemplate;
private MessageConfig messageConfig;
public DefaultRedisMessageTemplate(RedisTemplate redisTemplate, MessageConfig messageConfig) {
this.redisTemplate = redisTemplate;
this.messageConfig = messageConfig;
}
@Override
public boolean publishMessage(DelayMessage delayMessage) {
Preconditions.checkNotNull(delayMessage.getDuration(), "Message delay time must not be null");
try {
if (this.putMessageBody(delayMessage)) {
return this.putMessageId(delayMessage);
}
} catch (Exception e) {
logger.error("DelayMessage [{}] join queue failed", delayMessage, e);
}
return false;
}
private Boolean putMessageId(DelayMessage delayMessage) {
long score = delayMessage.getDuration().plusMillis(System.currentTimeMillis()).toMillis();
BoundZSetOperations zSetOperations = redisTemplate
.boundZSetOps(delayMessage.getChannelString());
Boolean result = zSetOperations.add(delayMessage.getMessageId(), score);
logger.info("DelayMessage join queue on topic [{}] with id [{}] result [{}] delay time [{}] ",
delayMessage.getChannelString(), delayMessage.getMessageId(), result, new Timestamp(score));
return result;
}
private Boolean putMessageBody(DelayMessage delayMessage) {
String bodyKey = messageConfig.getMessageBodyCacheKey(delayMessage.getMessageId());
Duration cacheSeconds = delayMessage.getDuration().plusSeconds(messageConfig.getMessageBodyCacheSeconds());
redisTemplate.opsForValue().set(bodyKey, delayMessage.getBodyString(), cacheSeconds);
// 初始化 ACK
String ackKey = messageConfig.getMessageAckCacheKey(delayMessage.getMessageId());
redisTemplate.opsForValue().set(ackKey, 0, cacheSeconds);
logger.info("Cache DelayMessage [{}] expired seconds [{}]", delayMessage, cacheSeconds);
return Boolean.TRUE.equals(redisTemplate.hasKey(bodyKey));
}
@Override
public boolean publishMessage(String topic, String message) {
try {
redisTemplate.convertAndSend(topic, message);
logger.info("Publish subscription message on topic [{}] body [{}]", topic, message);
return true;
} catch (Exception e) {
logger.error("Publish subscription message failed on topic [{}] body [{}] ", topic, message, e);
return false;
}
}
@Override
public boolean removeMessage(String topic, String messageId) {
boolean a = this.removeMessageId(topic, messageId);
boolean b = this.removeMessageBodyAndAck(messageId);
return a && b;
}
private Boolean removeMessageBodyAndAck(String messageId) {
String bodyKey = messageConfig.getMessageBodyCacheKey(messageId);
boolean a = Boolean.TRUE.equals(redisTemplate.delete(bodyKey));
if (logger.isDebugEnabled()) {
logger.debug("Remove message body [{}] with id [{}] result [{}]", bodyKey, messageId, a);
}
String ackKey = messageConfig.getMessageAckCacheKey(messageId);
boolean b = Boolean.TRUE.equals(redisTemplate.delete(ackKey));
if (logger.isDebugEnabled()) {
logger.debug("Remove message ack [{}] with id [{}] result [{}]", ackKey, messageId, b);
}
return a && b;
}
private boolean removeMessageId(String topic, String messageId) {
ZSetOperations zSetOperations = redisTemplate.opsForZSet();
Long count = zSetOperations.remove(topic, messageId);
if (logger.isDebugEnabled()) {
logger.debug("Remove message id [{}] on topic [{}] result [{}]", messageId, topic, count);
}
return 0 != PrimitiveUtils.getValue(count, 0);
}
@Override
public String getMessageBody(String messageId) {
String bodyKey = messageConfig.getMessageBodyCacheKey(messageId);
ValueOperations valueOperations = redisTemplate.opsForValue();
return valueOperations.get(bodyKey);
}
@Override
public long getMessageAck(String messageId) {
String ackKey = messageConfig.getMessageAckCacheKey(messageId);
ValueOperations valueOperations = redisTemplate.opsForValue();
Object ackValue = valueOperations.get(ackKey);
return Objects.nonNull(ackValue) ? Long.valueOf(ackValue.toString()) : 0L;
}
@Override
public boolean acknowledge(String topic, String messageId) {
try {
String ackKey = messageConfig.getMessageAckCacheKey(messageId);
ValueOperations valueOperations = redisTemplate.opsForValue();
Long count = valueOperations.increment(ackKey);
logger.info("Do acknowledge on topic [{}] DelayMessage id [{}] result [{}]", topic, messageId, count);
return 0 != PrimitiveUtils.getValue(count, 0);
} catch (Exception e) {
logger.error("Do acknowledge failed on topic [{}] DelayMessage id [{}] ", topic, messageId, e);
return false;
}
}
@Override
public boolean acknowledge(DelayMessage message) {
return acknowledge(message.getChannelString(), message.getMessageId());
}
@Override
public RedisTemplate getRedisTemplate() {
return this.redisTemplate;
}
}