[英]Java Drools - REST Call Timing Out - Out Of Memory
我正在 Java 項目中實現 Drools,以下依賴項的第 6 版:
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
<version>6.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>6.0.1.Final</version>
</dependency>
我打算通過調用使用 spring 4.3.0.RELEASE 構建的 REST API 來調用規則。 在我的配置類中,我從數據庫加載 drools 腳本:
@Configuration
@EnableWebMvc
@EnableAsync
@ComponentScan(basePackages = "com.bla.bla.api.app")
@ImportResource({ "classpath:datasources-context.xml" })
public class AppConfig {
private static final Log log = LogFactory.getLog(AppConfig.class);
public @Autowired IServiceDao serviceDao;
然后將規則作為@Repository
注釋類中的列表存儲在全局變量中:
@Repository
public class ServiceDao implements IServiceDao
在上面的 ServiceDao 中有一個方法,在 post 構造階段調用:
@PostConstruct
private void init() throws IOException {
log.debug("Initializing ruleevaluation API Context");
// Initializing rules:
serviceDao.initializeRules();
}
,從數據庫重新加載規則並初始化 drools 環境:
public void initializeRules() {
// 1. Load Rules:
log.debug("Initiating Rules...");
rules.clear();
rules = loadRules();
// 2. Initialize Drools Environment:
try {
initializeDrools();
} catch (DroolsParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
方法 'initializeDrools()' 實現如下:
private void initializeDrools() throws DroolsParserException, IOException {
PackageBuilder packageBuilder = new PackageBuilder();
RuleBase ruleBase = RuleBaseFactory.newRuleBase();
// This script will contain all the rules combined in one Drools script:
String completeRulesDroolsScript = "";
// Initialize script with object imports:
completeRulesDroolsScript = ""
+ "import com.bla.model.svc.RuleRequest \r\n"
+ "import com.bla.model.svc.RuleResponse \r\n\n\n";
if (rules != null) {
if (rules.size() > 0) {
for (RuleObject ruleObject : rules) {
// Add each individual Drools rule expression to the complete Drools script:
completeRulesDroolsScript += ruleObject.getExpression();
completeRulesDroolsScript = completeRulesDroolsScript .concat("\n\n\n");
}
}
}
try {
packageBuilder.addPackageFromDrl(new
StringReader(completeRulesDroolsScript));
org.drools.core.rule.Package rulesPackage = packageBuilder.getPackage();
ruleBase.addPackage(rulesPackage);
this.setWorkingMemory(ruleBase.newStatefulSession());
}
catch(Exception e) {
log.error("!!! Could not Initialize Drools Engine !!!");
}
}
接下來是 REST 方法,在一個單獨的控制器類中:
@RestController
public class RuleEvaluationController
它只是從 ServiceDao 類調用后端服務:
@PostMapping(value = "/evaluateRule")
public ResponseEntity<RuleEvaluationResponse> evaluateRuleData(
@RequestBody RuleEvaluationRequest ruleEvaluationRequest) {
RuleEvaluationResponse ruleEvaluationResponse = new RuleEvaluationResponse();
try {
// 1. get the parameters list:
log.debug(ruleEvaluationRequest.toString());
RuleEvaluationResponse response = serviceDao
.evaluateRule(ruleEvaluationRequest);
log.debug("response = " + response.getEntry());
return new ResponseEntity<RuleEvaluationResponse>(response,
HttpStatus.OK);
} catch (Exception e) {
log.error("!!!!! Exception Occurred:" + e.getMessage());
// set request id, and date in millis:
ruleevaluationResponse.setRequestId(UUID.randomUUID().toString());
ruleevaluationResponse.setDate(System.currentTimeMillis());
ruleevaluationResponse.setErrorCode(Constants.FAILURE);
ruleevaluationResponse.setErrorDescription(e.getMessage());
return new ResponseEntity<RuleEvaluationResponse>(ruleevaluationResponse,
HttpStatus.OK);
}
}
其中serviceDao.evaluateRule只是插入請求和響應對象,然后觸發規則:
public RuleEvaluationResponse evaluateRule(RuleEvaluationRequest request) {
RuleEvaluationResponse response = new RuleEvaluationResponse();
this.getWorkingMemory().insert(response);
this.getWorkingMemory().insert(request);
this.getWorkingMemory().fireAllRules();
log.debug("Response = " + response.getEntry());
return response;
}
起初這一切正常,我成功評估了規則並獲得了預期的響應。 然而,在 4 或 5 次 REST 調用之后,下一次 REST 調用將永遠持續下去並且永遠不會返回響應,並且過了一段時間我會收到內存不足錯誤。
誰能告訴我我在這里錯過了什么? 任何提示和建議都非常感謝。 如果以上信息不足,請隨時詢問更多詳細信息。
謝謝
您沒有提供所有代碼,所以也許您在其他地方進行了清理,但看起來您正在插入和調用.fireAllRules()
而沒有清理。 我的代碼與 KieSession 一起使用,看起來或多或少是這樣的:
kSession = container.newKieSession("name");
kSession.insert(...);
kSession.insert(...);
kSession.insert(...);
kSession.fireAllRules();
Object[] objects = kSession.getObjects();
kSession.dispose();
感謝您提供的提示和建議,它們有助於找到解決方案。
我解決了這個問題如下:
首先,我遷移到版本 6 的新語法。. ,使用 KieSession。
首先我初始化了 Kie 組件,如下所示:
// Define Kie Service from the Drools factory:
KieServices ks = KieServices.Factory.get();
// Define Drools Kie Repository to house the rules:
KieRepository kr = ks.getRepository();
// By default, a Kie File System is defined. In this case rules are NOT being
// read from the *.drl file, but instead fetched from Database.
KieFileSystem kfs = ks.newKieFileSystem();
// Write rules into the Kie file system. Specified file is irrelevant and can be
// empty, since we are not reading from *.drl file.
kfs.write("src/main/resources/com/rule/tempRules.drl", completeAccountingRulesDroolsScript);
// Define rule builder of the rules in file system object:
KieBuilder kb = ks.newKieBuilder(kfs);
// Build all rules in the script.kieModule is automatically deployed to
// KieRepository if successfully built.
kb.buildAll();
// Define new session container. This container is global and will be available
// for all subsequent rule invocations:
kContainer = ks.newKieContainer(kr.getDefaultReleaseId());
在我的 REST 調用中,我將代碼替換為以下內容:
kSession = kContainer.newKieSession();
kSession.insert(response);
kSession.insert(request);
kSession.fireAllRules();
Collection<? extends Object> objects = kSession.getObjects();
kSession.dispose();
現在變量 kContainer 是一個僅在啟動時初始化的全局變量。 在每次 REST 調用結束時,我都會處理會話。 以后的調用將為每個調用創建一個 kie 會話。 如果這是最好的方法,可以使用您的輸入。
@user3075118 @ 冷凍豌豆的羅迪
謝謝你的提示,這是解決問題的人。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.