Drools-存储多状态会话



我们在平台中实现了drools引擎,以便能够评估流中的规则。在我们的用例中,我们有一个包含多个实体的更改的更改检测流。

需要在一段时间内为流中的每个实体评估规则,并使其状态与其他实体(会话(不同。这些规则根据每个实体的状态生成警报。出于这个原因,实体应该进入边界,这样一个实体的状态就不会干涉其他实体。

为了实现这一点,我们为每个实体id创建一个会话作为Spring Bean,并将其存储在inMemory HashMap中。因此,每当一个实体到达时,我们都会尝试使用它的Id在inMemory Map上找到它的会话。如果我们得到null返回,我们就会创建它。

它似乎不是实现这一目标的正确方法。因为它没有提供灾难恢复策略,也没有提供出色的内存管理。

我们可以使用某种inMemory数据库,如Redis或Memchached。但我不认为它能够准确地恢复有状态的会话。

有人知道如何以正确的方式使用具有多会话的嵌入式Drools实现灾难恢复和良好的内存管理吗?该平台是否提供了一些解决方案?

非常感谢您对的关注和支持

答案不是尝试持久化和重用会话,而是持久化一个为实体的当前状态建模的对象。

您当前的工作流程是:

  1. 实体到达您的应用程序(来自更改检测流或其他地方(
  2. 您在hashmap上进行查找以获得存储了实体状态的Session
  3. 触发规则,更新会话(可能还有实体(
  4. 您将会话保存在内存中

您的工作流程应该是什么是这样的:

  1. (相同(实体到达您的应用程序
  2. 在外部数据源上查找实体的状态,例如从数据库或数据存储中查找
  3. 您触发规则,传入实体状态。不是更新会话,而是更新状态实例
  4. 您可以将状态持久化到外部数据源

如果添加适当的直写缓存,则可以保证性能和一致性。如果您为数据源实现了适当的锁定/事务处理,这也将允许您横向扩展应用程序。


这是一个玩具示例。

假设我们有一个为图书馆建模的应用程序,用户可以在其中结账。用户一次只能签出总共3本书。

我们收到的"事件"模拟了图书登记或退房事件:

class BookBorrowEvent {
int userId;
int bookId;
EventType eventType; // EventType.CHECK_IN or EventType.CHECK_OUT
}

在外部数据源中,我们维护UserState记录——可能是传统RDBMS或聚合中的一个不同记录;我们如何存储它与这个例子并不相关。但假设我们从数据源返回的UserState记录看起来像这样:

class UserState {
int userId;
int[] borrowedBookIds;
}

当我们收到事件时,我们将首先从外部数据存储(或内部管理的直通写缓存(中检索用户状态,然后将UserState添加到规则输入中。当然,我们应该适当地处理我们的会话(在使用后处理它们,根据需要使用会话池(。

public void handleBookBorrow(BookBorrowEvent event) {
UserState state = getUserStateFromStore(event.getUserId());
KieSession kieSession = ...; 
kieSession.insert( event );
kieSession.insert( state ); 
kieSession.fireAllRules();
persistUserStateToStore(state);
}

然后,您的规则将针对UserState实例进行工作,而不是将值存储在局部变量中。

一些示例规则:

rule "User borrows a book"
when
BookBorrowEvent( eventType == EventType.CHECK_OUT,
$bookId: bookId != null )
$state: UserState( $checkedOutBooks: borrowedBookIds not contains $bookId )
Integer( this < 3 ) from $checkedOutBooks.length
then
modify( $state ) { ... }
end
rule "User returns a book"
when
BookBorrowEvent( eventType == EventType.CHECK_IN,
$bookId: bookId != null )
$state: UserState( $checkedOutBooks: borrowedBookIds contains $bookId )
then
modify( $state ) { ... }
end

很明显,这是一个玩具般的例子,但你可以很容易地为用户试图签出一本书的副本、用户试图归还他们没有签出的书、如果用户超过3个最大图书借阅限制则返回错误、为允许的签出长度添加基于时间的逻辑等情况添加附加规则。

即使您使用基于流的处理以便利用时态运算符,此工作流仍然有效,因为您将在收到状态实例时将其传递到评估流中。当然,在这种情况下,出于性能原因,正确实现直写缓存将更为重要(除非您的临时运算符足够宽容,允许一些数据源事务延迟(。您需要做的唯一更改是重新调整规则的焦点,使其数据持久性指向状态对象,而不是会话本身——通常不建议这样做,因为会话是为处理而设计的。

最新更新