客户自定义时间执行事件

基本需求:前端客户指定任意时间执行动作,如:定时发布公告、定时发布产品、定时提醒

实现思路:利用 redis+mq

实现逻辑:利用redis 的key 失效事件触发任务

实现准备:

redis版本 2.8.0+

修改redis.conf中的notify-keyspace-events Ex,默认为notify-keyspace-events ""
也可以使用执行命令:CONFIG set notify-keyspace-events Ex   (采用此种方法若重启redis需重新设置)

 

代码如下:

redis配置如下


    @Bean
    RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
//        container.addMessageListener(new RedisExpiredListener(), new PatternTopic("__keyevent@0__:expired"));
        return container;
    }

key失效监听:

@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {

    public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
        super(listenerContainer);
    }

    @Autowired(required = false)
    private DefaultMQProducer producer;

    @Resource
    private RedisUtil redisUtil;

    @Value("${notice.redis.send.tempValueKeyPrefix:NOTICE:SEND:TEMP:VALUE:}")
    private String tempValueKeyPrefix;

    /**
     * 针对redis数据失效事件,进行数据处理
     *
     * @param message
     * @param pattern
     */
    @Override
    public void onMessage(Message message, byte[] pattern) {
        // 用户做自己的业务处理即可,注意message.toString()可以获取失效的key
        String expiredKey = message.toString();
        if (expiredKey.startsWith("invalid:")) {
            //如果是Order:开头的key,进行处理
            System.out.println("----------------------------------------------------------------------");
            System.out.println(expiredKey);
            System.out.println("channel:" + new String(message.getChannel()));
            org.apache.rocketmq.common.message.Message msg = null;
            try {
                ///截取MQ_TOPIC,MQ_TAG,redisKey
                String[] key = expiredKey.split(":");
                String vk = String.valueOf(redisUtil.get(tempValueKeyPrefix + key[3]));
                if (redisUtil.delete(tempValueKeyPrefix + key[3])){
                    msg = new org.apache.rocketmq.common.message.Message(key[1], key[2], vk.getBytes("utf-8"));
                    SendResult result = producer.send(msg);
                    if (result.getSendStatus() == SendStatus.SEND_OK) {
                        System.out.println("redis超时监听消息发送成功:" + expiredKey);
                    }
                    return;
                }
            } catch (Exception e) {
                // 消息发送失败,需要进行重试处理,可重新发送这条消息或持久化这条数据进行补偿处理
                System.out.println(e.getMessage());
            }
            System.out.println("----------------------------------------------------------------------");
        }
    }
}

接口:

    /**
     * @Title: execute
     * @Description: TODO(根据传入时间判断是否立即执行)
     * @author wolf
     * @date 2020年11月18日10:54:56
     * @param type 类型
     * @param vk redisKey
     * @param targetTime 执行时间
     * @return
     */
    @RequestMapping(value = "execute")
    MsgModel<?> execute(@NotNull EnumTopic type,@NotNull String vk,@NotNull Long targetTime) throws Exception;

实现:

@RestController
@Service
public class SuperTimedTaskServiceImpl  implements SuperTimedTaskService {

    @Resource
    private RedisUtil redisUtil;
    @Autowired(required = false)
    private DefaultMQProducer producer;

    @Value("${notice.redis.send.tempValueKeyPrefix:NOTICE:SEND:TEMP:VALUE:}")
    private String tempValueKeyPrefix;
    @Value("${notice.redis.send.redisValueKeyPrefix}")
    private String redisValueKeyPrefix;

    @Override
    public MsgModel<?> execute(EnumTopic type, String vk, Long targetTime) throws Exception {
        //判断失效时间
        ///如果失效时间在正负10秒则直接进入队列
        Long runTime = (targetTime - System.currentTimeMillis()) / 1000;
        if(runTime<2){
            org.apache.rocketmq.common.message.Message msg=null;
            try {
                msg = new org.apache.rocketmq.common.message.Message(type.getEnumTopic(), type.getEnumTopic(), vk.getBytes("utf-8"));
                SendResult result = producer.send(msg);
                return new MsgModel<>("直接进入队列成功", RespStatusEnum.SUCCESS);
            } catch (Exception e) {
                // 消息发送失败,需要进行重试处理,可重新发送这条消息或持久化这条数据进行补偿处理
                throw e;
            }
        }

        ///否则生成失效key放入redis 同时把需要处理的数据单独存储redis中
        SnowFlake idWorker = new SnowFlake(0, 0);
        String key=String.valueOf(idWorker.nextId());
        String redisKey= tempValueKeyPrefix + key;
        String invalidRedisKye=new StringBuffer("invalid:").append(type.getEnumTopic()).append(":").append(type.getEnumTopic()).append(":").append(key).toString();
        try {
            redisUtil.set(redisKey,vk);
            redisUtil.set(invalidRedisKye,"123",runTime);
        } catch (Exception e) {
            redisUtil.del(redisKey);
            redisUtil.del(invalidRedisKye);
            throw e;
        }
         return new MsgModel<>("成功", RespStatusEnum.SUCCESS);
    }




}

枚举:


// 定义数据库类型枚举
public enum EnumTopic {

    TEST("topicTest555", "tagTest666");
    ;
    private String enumTopic;
    private String enumTag;

    private EnumTopic(String enumTopic, String enumTag) {
        this.enumTopic = enumTopic;
        this.enumTag = enumTag;
    }

    public String getEnumTopic() {
        return this.enumTopic;
    }

    public String getEnumTag() {
        return this.enumTag;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值