| Crates.io | moduforge-rules-engine |
| lib.rs | moduforge-rules-engine |
| version | 0.5.0 |
| created_at | 2025-06-13 07:09:40.15796+00 |
| updated_at | 2025-08-19 09:30:41.863624+00 |
| description | moduforge 引擎规则 |
| homepage | https://github.com/Cassielxd/moduforge-rs |
| repository | https://github.com/Cassielxd/moduforge-rs |
| max_upload_size | |
| id | 1711163 |
| size | 381,826 |
moduforge-rules-engine 引擎是一个对业务友好的开源业务规则引擎(BRE),基于 Zen Engine进行二次开发,完全兼容zen-engine,在此基础上 增加了规则引擎的易用性,并添加了规则引擎的扩展功能,把State 注入上下文中。在自定义方法中可以获取State对象。
要使用 Noop(默认)加载器执行简单决策,您可以使用以下代码:
use serde_json::json;
use mf_rules_engine::DecisionEngine;
use mf_rules_engine::model::DecisionContent;
async fn evaluate() {
let decision_content: DecisionContent = serde_json::from_str(include_str!("jdm_graph.json")).unwrap();
let engine = DecisionEngine::default();
let decision = engine.create_decision(decision_content.into());
let result = decision.evaluate(&json!({ "input": 12 })).await;
}
另外,您也可以使用 Decision::from 函数间接创建决策,而无需构建引擎。
对于更高级的用例,当您需要加载多个决策并使用图时,您可以使用以下预制的加载器之一:
Arc<DecisionContent> 实例假设您有一个位于 /app/decisions 下的决策模型文件夹(.json 文件),您可以按以下方式使用 FilesystemLoader:
use serde_json::json;
use mf_rules_engine::DecisionEngine;
use mf_rules_engine::loader::{FilesystemLoader, FilesystemLoaderOptions};
async fn evaluate() {
let engine = DecisionEngine::new(FilesystemLoader::new(FilesystemLoaderOptions {
keep_in_memory: true, // 可选,保持在内存中以提高性能
root: "/app/decisions"
}));
let context = json!({ "customer": { "joinedAt": "2022-01-01" } });
// 如果您计划多次使用它,可以缓存 JDM 以获得轻微的性能提升
// 在绑定(其他语言)的情况下,这种提升会更大
{
let promotion_decision = engine.get_decision("commercial/promotion.json").await.unwrap();
let result = promotion_decision.evaluate(&context).await.unwrap();
}
// 或者按需加载
{
let result = engine.evaluate("commercial/promotion.json", &context).await.unwrap();
}
}
您可以通过实现 DecisionLoader trait 为 zen 引擎创建自定义加载器。
以下是 MemoryLoader 的实现示例:
use std::collections::HashMap;
use std::sync::{Arc, RwLock};
use mf_rules_engine::loader::{DecisionLoader, LoaderError, LoaderResponse};
use mf_rules_engine::model::DecisionContent;
#[derive(Debug, Default)]
pub struct MemoryLoader {
memory_refs: RwLock<HashMap<String, Arc<DecisionContent>>>,
}
impl MemoryLoader {
pub fn add<K, D>(&self, key: K, content: D)
where
K: Into<String>,
D: Into<DecisionContent>,
{
let mut mref = self.memory_refs.write().unwrap();
mref.insert(key.into(), Arc::new(content.into()));
}
pub fn get<K>(&self, key: K) -> Option<Arc<DecisionContent>>
where
K: AsRef<str>,
{
let mref = self.memory_refs.read().unwrap();
mref.get(key.as_ref()).map(|r| r.clone())
}
pub fn remove<K>(&self, key: K) -> bool
where
K: AsRef<str>,
{
let mut mref = self.memory_refs.write().unwrap();
mref.remove(key.as_ref()).is_some()
}
}
impl DecisionLoader for MemoryLoader {
fn load<'a>(&'a self, key: &'a str) -> impl Future<Output=LoaderResponse> + 'a {
async move {
self.get(&key)
.ok_or_else(|| LoaderError::NotFound(key.to_string()).into())
}
}
}