在运行时替换Drools .drl文件

时间:2018-06-16 00:02:54

标签: java drools kie

环境

  • Drools版本:7.6.0 Final
  • Java 8

目标

我的应用程序是一个服务器程序,其中包含执行Drools规则的功能。 Drools定义位于已配置文件夹中的.drl文件中。在程序启动时,我创建了一个带有几行Java代码的KieContainer。然后我使用文件夹监视器来监视文件更改,在这种情况下,我创建了一个新的辅助KieContainer。如果失败(由kieBuilder.getResults().hasMessages(Message.Level.ERROR)检查),则会记录错误,规则人员可以修复它。此外,现场的KieContainer将替换为新的。

我有一个工作版本,但似乎有副作用。

我不打算使用Maven和KieScanner重新部署新版本。我使用Maven,但我真的不认为这是我的理由。

也不是具有REST API的执行服务器

我的解决方案应该很简单。与Logback相比,它甚至可以在幕后自行重新加载logback.xml配置文件。我的感觉是,这比必要的更复杂。

代码

create()方法在程序启动时使用,然后在文件系统看到更改时再次使用:

private KieContainer create() {
    KieServices kieServices = KieServices.Factory.get();
    KieFileSystem kieFileSystem = kieServices.newKieFileSystem();

    File[] rulesFiles = rulesDir.listFiles((dir, name) -> name.endsWith(".drl"));
    for (File rulesFile : rulesFiles) {
        final Resource resource = ResourceFactory.newFileResource(rulesFile.getAbsolutePath());
        String targetPath = rulesFile.getAbsolutePath().replaceAll("\\\\", "\\/"); //slashes must be standardized for it to work
        resource.setTargetPath(targetPath);
        kieFileSystem.write(resource);
    }

    KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem);
    kieBuilder.buildAll();
    Results results = kieBuilder.getResults();
    if (results.hasMessages(Message.Level.ERROR)) {
        //logging not shown for brevity
        //PROBLEM: even though we abort here, it seems that the lines above modify the kieContainer that is currently in use!
        throw new IllegalStateException("Errors occurred while reading rules.");
    }

    KieModule kieModule = kieBuilder.getKieModule();
    return kieServices.newKieContainer(kieModule.getReleaseId());
}

当Drools文件出现问题时,创建将中止,并保留当前的KieContainer。

如果成功,则要替换的代码如下:

/**
 * Called from the directory watcher, so we are in a separate thread here.
 */
private void refresh() {
    try {
        KieContainer oldContainer;

        //first try to create a new one behind the scenes, while requests concurrently still use the old one:
        KieContainer newContainer = create();
        //then swap it out, thread safe:
        synchronized (this) {
            oldContainer = this.kieContainer;
            this.kieContainer = newContainer;
        }
        //log not shown for brevity

        //then we have time to dispose the old one while no one waits:
        if (oldContainer != null) {
            //the current container may still be used by current threads.
            //i am not aware what dispose does in this regard, i think we should wait a bit until all use is finished.
            Thread.sleep(2000);
            oldContainer.dispose();
        }

    } catch (Exception e) {
        //log not shown for brevity
    }
}

问题

当有人编辑.drl个文件并且出现错误时,有几次发生了奇怪的事情。 KieContainer未被替换(根据需要),但Drools方法调用的副作用似乎已经发生。

KieServices是单身,很好。 我们创建一个新的KieFileSystem,看起来不错,新的断开连接的实例。 我们打电话给kieFileSystem.write(),应该没问题? 然后kieServices.newKieBuilder()再次返回一个新的断开连接的实例。 因此kieBuilder.buildAll()应该没问题?

调试时,我可以看到两个KieBuilder都有相同的KieModule实例?

错误和中止刷新的一种方式是Drools编辑人员复制.drl文件,然后打算编辑它。文件系统接收更改,并且加载规则失败,因为我们有一个重复的文件(相同的内容,相同的包)。

问题

我的代码出了什么问题,我可以更改什么才能使新的KieContainer创建与以前加载的完全断开?

0 个答案:

没有答案