方案一

由于RocketMQ只有固定的延时等级,如下:

public enum DelayTimeLevel {
    NO_NEED_TO_DELAY(0, "无需延迟消费"),
    ONE_SECOND(1, "1秒"),
    FIVE_SECONDS(2, "5秒"),
    TEN_SECONDS(3, "10秒"),
    THIRTY_SECONDS(4, "30秒"),
    ONE_MINUTE(5, "1分钟"),
    TWO_MINUTES(6, "2分钟"),
    THREE_MINUTES(7, "3分钟"),
    FOUR_MINUTES(8, "4分钟"),
    FIVE_MINUTES(9, "5分钟"),
    SIX_MINUTES(10, "6分钟"),
    SEVEN_MINUTES(11, "7分钟"),
    EIGHT_MINUTES(12, "8分钟"),
    NINE_MINUTES(13, "9分钟"),
    TEN_MINUTES(14, "10分钟"),
    ELEVEN_MINUTES(15, "11分钟"),
    TWELVE_MINUTES(16, "12分钟"),
    ONE_HOUR(17, "1小时"),
    TWO_HOUR(18, "2小时");
}

任意时间的定时,使用RocketMQ本身是实现不了的,以下提供了通过借助RocketMQ实现任意时间的定时消息。

总体叙述:通过计算当前时间和定时的时间之间的秒数,去匹配RocketMQ的延时等级,如果没有匹配到,找到第一个比目前时间秒数小或者相等的级别,作为延时等级向MQ推送消息,以此类推,知道找到合适的延时等级。

算法图示

算法图示

时间变化图示

时间变化图示
优点:消息及时;
缺点:MQ里面有冗余的消息存在;

该方案具体的代码可以站内邮箱联系我。

方案二

通过定时任务去读取数据库,定时扫描,当扫描到满足推送的消息时,推送到MQ即可。
spring的定时任务,quartz定时任务。
优点:MQ不会存在冗余消息;
缺点:发送消息有延迟,取决于定时扫描的周期,太快了可能会影响性能,太慢了又不准时。