You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Drools优惠券生成规则触发次数超出预期问题排查

Drools优惠券规则重复触发问题排查

我是Drools新手,正在跟着《Mastering JBoss Drools 6》第二章的示例学习。这个示例需要创建Customer和Order对象,实现以下逻辑:

  • 订单包含5个商品的客户,归类为SILVER等级
  • 单价超过500的商品,归类为HIGH_RANGE
  • SILVER等级客户需要生成Coupon
  • 订单商品数≥2的SILVER客户可享受10%折扣

我写了对应的规则和测试用例,预期规则总触发次数是8次(5次商品分类+1次客户分类+1次折扣规则+1次优惠券生成),但实际触发了9次,其中优惠券生成规则触发了两次。测试日志显示优惠券生成规则执行了两次,但最终只能查到第二个优惠券;调试模式下触发次数符合预期(8次)。后续排查发现:用Lombok的@EqualsAndHashCode注解,或者自定义包含discount字段的hashCode方法时会出现这个问题,只保留equals方法就恢复正常。


相关规则代码

add-discount.drl

rule "High Range order - 10% discount"
    when
        $o: Order($lines: orderLines, orderLines.size >= 2, $customer: customer, discount == null)
        $c: Customer(category == Customer.Category.SILVER, this == $customer)
        forall(
            OrderLine(this memberOf $lines, $item: item)
            Item(this == $item, category == Item.Category.HIGH_RANGE)
        )
    then
        modify($o){
            setDiscount(new Discount(10.0))
        }
end

classify-customer-rules.drl

rule "Classify Customer by order size"
    when
        $o: Order( orderLines.size >= 5, $customer: customer )
        $c: Customer(this == $customer, category == Customer.Category.NA)
    then
        modify($c){
            setCategory(Customer.Category.SILVER)
        }
end

classify-items-rules.drl

rule "Classify Item - Low Range"
    when
        $i: Item(cost < 200, category == Category.NA)
    then
        $i.setCategory(Category.LOW_RANGE);
        update($i);
end

rule "Classify Item - Mid Range"
    when
        $i: Item(cost > 200 && cost < 500, category == Category.NA)
    then
        $i.setCategory(Category.MID_RANGE);
        update($i);
end

rule "Classify Item - High Range"
    when
        $i: Item(cost >= 500, category == Category.NA)
    then
        $i.setCategory(Category.HIGH_RANGE);
        update($i);
end

coupons-creation.drl

rule "Create Coupons for silver customer"
    when
        $o: Order($customer: customer)
        $c: Customer(this == $customer, category == Customer.Category.SILVER)
    then
        Coupon x = new Coupon($c, $o, Coupon.CouponType.POINTS);
        System.out.println(x);
        insert(x);
end

测试代码

@Test
void orderDiscountTest() {
    KieSession kieSession = Util.getDefaultKieSession();
    Order o = ModelFactory.getOrderWithFiveHighRangeItems();

    kieSession.insert(o.getCustomer());
    kieSession.insert(o.getOrderLines().get(0));
    kieSession.insert(o.getOrderLines().get(1));
    kieSession.insert(o.getOrderLines().get(2));
    kieSession.insert(o.getOrderLines().get(3));
    kieSession.insert(o.getOrderLines().get(4));
    kieSession.insert(o.getOrderLines().get(0).getItem());
    kieSession.insert(o.getOrderLines().get(1).getItem());
    kieSession.insert(o.getOrderLines().get(2).getItem());
    kieSession.insert(o.getOrderLines().get(3).getItem());
    kieSession.insert(o.getOrderLines().get(4).getItem());
    kieSession.insert(o);

    int fired = kieSession.fireAllRules();

    assertEquals(8, fired);
    assertEquals(Customer.Category.SILVER, o.getCustomer().getCategory());
    assertNotNull(o.getDiscount());
    assertEquals(10.0, o.getDiscount().getPercentage());
    assertEquals(Item.Category.HIGH_RANGE, o.getOrderLines().get(0).getItem().getCategory());
    assertEquals(Item.Category.HIGH_RANGE, o.getOrderLines().get(1).getItem().getCategory());
    assertEquals(Item.Category.HIGH_RANGE, o.getOrderLines().get(2).getItem().getCategory());
    assertEquals(Item.Category.HIGH_RANGE, o.getOrderLines().get(3).getItem().getCategory());
    assertEquals(Item.Category.HIGH_RANGE, o.getOrderLines().get(4).getItem().getCategory());

    Collection<Coupon> coupons = Util.getFactsFromSession(kieSession, Coupon.class);
    coupons.forEach(x -> System.out.println(x));
    assertEquals(1, coupons.size());
}

测试日志

12:54:47.607 [main] DEBUG org.drools.core.impl.KnowledgeBaseImpl - Starting Engine in PHREAK mode
12:54:47.730 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is nw FIRING_ALL_RULES
12:54:47.732 [main] DEBUG org.drools.core.common.DefaultAgenda - Fire Loop
12:54:47.795 [main] DEBUG org.drools.core.common.DefaultAgenda - Fire Loop
Coupon created com.example.droolstut.model.Coupon@b14cb989
12:54:47.797 [main] DEBUG org.drools.core.common.DefaultAgenda - Fire Loop
12:54:47.797 [main] DEBUG org.drools.core.common.DefaultAgenda - Fire Loop
12:54:47.799 [main] DEBUG org.drools.core.common.DefaultAgenda - Fire Loop
12:54:47.806 [main] DEBUG org.drools.core.common.DefaultAgenda - Fire Loop
Coupon created com.example.droolstut.model.Coupon@424f842a
12:54:47.806 [main] DEBUG org.drools.core.common.DefaultAgenda - Fire Loop
12:54:47.806 [main] DEBUG org.drools.core.common.DefaultAgenda - Fire Loop
12:54:47.806 [main] DEBUG org.drools.core.common.DefaultAgenda - State was FIRING_ALL_RULES is nw HALTING
12:54:47.806 [main] DEBUG org.drools.core.common.DefaultAgenda - State was HALTING is nw INACTIVE
Coupon found: com.example.droolstut.model.Coupon@424f842a
Coupon found: com.example.droolstut.model.Coupon@424f842a

排查补充信息

EDIT 1日志

Order(orderId=1, date=Thu Jan 01 05:30:00 IST 1970, customer=Customer(customerId=1, age=40, name=John Doe, email=johndoe@example.com, category=SILVER), orderLines=[OrderLine(item=com.example.droolstut.model.Item@38c70399, quantity=1), OrderLine(item=com.example.droolstut.model.Item@5245e3d4, quantity=1), OrderLine(item=com.example.droolstut.model.Item@6bc4c40f, quantity=1), OrderLine(item=com.example.droolstut.model.Item@8543a44a, quantity=1), OrderLine(item=com.example.droolstut.model.Item@9ec28485, quantity=1)], state=PENDING, discount=null) Customer(customerId=1, age=40, name=John Doe, email=johndoe@example.com, category=SILVER)
com.example.droolstut.model.Coupon@2753dad2
12:16:02.399 [main] DEBUG org.drools.core.common.DefaultAgenda - Fire Loop
12:16:02.400 [main] DEBUG org.drools.core.common.DefaultAgenda - Fire Loop
12:16:02.402 [main] DEBUG org.drools.core.common.DefaultAgenda - Fire Loop
12:16:02.408 [main] DEBUG org.drools.core.common.DefaultAgenda - Fire Loop
Order(orderId=1, date=Thu Jan 01 05:30:00 IST 1970, customer=Customer(customerId=1, age=40, name=John Doe, email=johndoe@example.com, category=SILVER), orderLines=[OrderLine(item=com.example.droolstut.model.Item@5dc27ea9, quantity=1), OrderLine(item=com.example.droolstut.model.Item@77415ee4, quantity=1), OrderLine(item=com.example.droolstut.model.Item@90c03f1f, quantity=1), OrderLine(item=com.example.droolstut.model.Item@aa3f1f5a, quantity=1), OrderLine(item=com.example.droolstut.model.Item@c3bdff95, quantity=1)], state=PENDING, discount=Discount(percentage=10.0)) Customer(customerId=1, age=40, name=John Doe, email=johndoe@example.com, category=SILVER)
com.example.droolstut.model.Coupon@10e5ecb2

EDIT 2自定义hashCode与equals方法

@Override
public int hashCode() {
    int hash = 3;
    hash = 17 * hash + Objects.hashCode(this.orderId);
    hash = 17 * hash + Objects.hashCode(this.date);
    hash = 17 * hash + Objects.hashCode(this.customer);
    hash = 17 * hash + Objects.hashCode(this.orderLines);
    hash = 17 * hash + Objects.hashCode(this.state);
    hash = 17 * hash + Objects.hashCode(this.discount);
    return hash;
}

@Override
public boolean equals(Object obj) {
    if (obj == null) {
        return false;
    }
    if (getClass() != obj.getClass()) {
        return false;
    }
    final Order other = (Order) obj;
    if (!Objects.equals(this.orderId, other.orderId)) {
        return false;
    }
    if (!Objects.equals(this.date, other.date)) {
        return false;
    }
    if (!Objects.equals(this.customer, other.customer)) {
        return false;
    }
    if (!Objects.equals(this.orderLines, other.orderLines)) {
        return false;
    }
    if (this.state != other.state) {
        return false;
    }
    if (!Objects.equals(this.discount, other.discount)) {
        return false;
    }
    return true;
}

内容的提问来源于stack exchange,提问作者Karthik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 20:30:44