优惠券过期使用 RocketMQ 的延时任务实现

实现优惠券过期功能可以通过 RocketMQ 的延时消息来处理。延时消息可以使消息在一段可预见的时间后被消费,这对于实现定时任务和处理过期机制非常有效。下面是一个详细的项目示例和代码说明,描述如何使用 RocketMQ 来管理优惠券的过期处理。

项目背景

假设我们有一个电商系统,用户在下单时可以使用优惠券。每张优惠券都有一个有效期,当优惠券过期时,我们需要将其标记为无效,以防止在后续订单中使用。

项目结构

  1. 优惠券服务(Coupon Service):管理优惠券的创建、使用和过期管理。
  2. RocketMQ 消息组件:用于发送和消费延时消息。
  3. 延时消息机制:通过 RocketMQ 发送优惠券过期的延时消息。

核心代码实现

1. 实体类

优惠券模型

@Entity
public class Coupon {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String code;
    private LocalDateTime expirationDate;
    private boolean valid;  // 表示优惠券是否有效

    // Getters and setters
}

2. 优惠券服务

优惠券接口

@RestController
@RequestMapping("/api/coupons")
public class CouponController {

    @Autowired
    private CouponService couponService;

    @PostMapping("/create")
    public ResponseEntity createCoupon(@RequestBody Coupon coupon) {
        Coupon createdCoupon = couponService.createCoupon(coupon);
        return ResponseEntity.status(HttpStatus.CREATED).body(createdCoupon);
    }
}

优惠券服务

@Service
public class CouponService {

    @Autowired
    private CouponRepository couponRepository;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    public Coupon createCoupon(Coupon coupon) {
        coupon.setValid(true);
        Coupon savedCoupon = couponRepository.save(coupon);

        // 计算延时时间:优惠券过期时间 - 当前时间
        long delayTime = Duration.between(LocalDateTime.now(), coupon.getExpirationDate()).toMillis();

        // 发送延时消息
        rocketMQTemplate.syncSend("coupon-expiration-topic",
                MessageBuilder.withPayload(savedCoupon.getId())
                        .build(),
                1000, // 超时时间
                delayTime); // 延时毫秒数

        return savedCoupon;
    }
}

3. RocketMQ 延时消息消费

@Service
@RocketMQMessageListener(topic = "coupon-expiration-topic", consumerGroup = "coupon-consumer-group")
public class CouponExpirationListener implements RocketMQListener {

    @Autowired
    private CouponRepository couponRepository;

    @Override
    public void onMessage(Long couponId) {
        Optional couponOpt = couponRepository.findById(couponId);
        if (couponOpt.isPresent()) {
            Coupon coupon = couponOpt.get();
            if (coupon.getExpirationDate().isBefore(LocalDateTime.now())) {
                coupon.setValid(false); // 标记为无效
                couponRepository.save(coupon);
                System.out.println("Coupon " + couponId + " has been marked as invalid.");
            }
        }
    }
}

代码说明

  1. 实体类
    • Coupon 类代表一张优惠券,包括优惠券代码、过期时间和有效性状态。
  2. 优惠券服务
    • createCoupon 方法负责创建新的优惠券,并发送一条延时消息,这条消息将在优惠券到期时被消费。
  3. 延时消息机制
    • 使用 rocketMQTemplate.syncSend 方法发送延时消息,其中 delayTime 计算为优惠券过期时间减去当前时间得到的毫秒数。
  4. 消息消费
    • CouponExpirationListener 监听指定的主题,消费消息并将对应优惠券标记为无效。这一过程依赖于 RocketMQ 的延时消息特性。

主要作用

  • 自动过期:通过延时消息自动管理优惠券的过期,无需手动干预。
  • 降低复杂度:避免手动调度任务或定时任务,完全依靠消息中间件实现。
  • 节省资源:只有在消息到期时才触发处理逻辑,节省系统资源。
  • 高效性:RocketMQ 的高性能保证了延时消息的高效处理,使得过期机制既可靠又快速。

通过这种方式,可以很容易地处理类似的过期场景,不仅限于优惠券,也适用于租赁、订阅等其他领域的到期处理。