Skip to content

Latest commit

 

History

History
84 lines (62 loc) · 4.81 KB

emall-appendix-multi-transfer-station.md

File metadata and controls

84 lines (62 loc) · 4.81 KB

附录:多个配送中转站

在现实情况下,一个需要配送的商品,往往需要经过多个配送中转站才能到客户手里。其逻辑如下:

graph LR
	qs1(签收)--> end1{终点?}
	end1 --No--> ps1(配送)
	ps1 --> qs1
	end1 --Yes--> finished(配送完成)
Loading

大家可以看到这里有个环状结构,下面我们用Nature 来解决这个问题。元数据和关系定义如下:

INSERT INTO meta
(meta_type, meta_key, description, version, states, fields, config)
VALUES('B', 'delivery', '', 1, '', '', '');

INSERT INTO meta
(meta_type, meta_key, description, version, states, fields, config)
VALUES('B', 'deliveryState', '', 1, 'new|finished', '', '{"master":"B:delivery:1"}');

-- delivery --> deliveryState
INSERT INTO relation
(from_meta, to_meta, settings)
VALUES('B:delivery:1', 'B:deliveryState:1', '{"target":{"state_add":["new"], "append_para":[0,1]}}');

-- deliveryState --> delivery
INSERT INTO relation
(from_meta, to_meta, settings)
VALUES('B:deliveryState:1', 'B:delivery:1', '{"selector":{"state_all":["finished"], "context_all":["mid"]}, "use_upstream_id":true, "executor":{"protocol":"localRust","url":"nature_demo:multi_delivery"}}');

上述脚本来源于 nature-demo::doc::demo-multi-delivery.sql

delivery:是具体的物流信息,如包含从哪里到哪里。这里我们模拟两次中转: A->B->C->D, 货物从A出发, D是终点。

deliveryState:是物流的状态,为简单起见,我们我们只有 new 和 finished 两个状态。

delivery --> deliveryState :用于自动生成状态为 new 的配送状态数据(无需编码),具体介绍请参考之前示例

  • Nature 要点:"append_para":[0,1] 是说我们要从上游复制 para 到下游,具体请看relation.md。在本示例里我们将配送的起始地与目的地一起放到了 Instance.para 中。形式如 “A/B”。

deliveryState --> delivery:用于当前配送结束后,生成后续的配送任务。

  • Nature 要点:如果指定了多个选择器则选择器之间是的关系,既必须同时满足才能触发执行器deliveryState --> delivery 用到了state_allcontext_all两个选择器,两个都满足后才能执行multi_delivery
  • Nature 要点delivery --> deliveryStatedeliveryState --> delivery 构成了一个业务上的循环,而我们避免了 loop, for 和 while 等这些编程元素。

来看下我们的编码工作,配送单的输入请参考:nature-demo::multi_delivery.rs, 执行器的代码请参考:nature_demo::multi_delivery。在输入端我们只需要提交一个配置单,但需要提交三个状态数据以说明配送的状态,前两个需要指定 Instance.context 为 “mid”, 最后一个需要制定 Instance.context 为非“mid”(在这里我们用了“end”)。在执行器的代码中,有下面的代码,用于生成下次配送任务的起止地点:

    ins.para = match para {
        "A/B" => "B/C".to_string(),
        "B/C" => "C/D".to_string(),
        "C/D" => "error".to_string(),
        _ => "err2".to_string()
    };

"C/D" 或 "_" 两个分支用于验证 配置设置的正确性以及 Nature 执行的正确性。让我们看下是否有 Instance.para 为 "error" 或 "err2" 的实例产生。运行下面的代码:

nature.exe
cargo.exe test --color=always --package nature-demo --lib multi_delivery::test

运行后的数据如下:

ins_key context states state_version from_key
B:delivery:1|0|A/B 0
B:delivery:1|0|B/C 0 B:deliveryState:1|0|A/B|2
B:delivery:1|0|C/D 0 B:deliveryState:1|0|B/C|2
B:deliveryState:1|0|A/B ["new"] 1 B:delivery:1|0|A/B|0
B:deliveryState:1|0|A/B {"mid":"mid"} ["finished"] 2
B:deliveryState:1|0|B/C ["new"] 1 B:delivery:1|0|B/C|0
B:deliveryState:1|0|B/C {"mid":"mid"} ["finished"] 2
B:deliveryState:1|0|C/D ["new"] 1 B:delivery:1|0|C/D|0
B:deliveryState:1|0|C/D {"end":"end"} ["finished"] 2

很高兴,我们又一次见证 Nature 对流程的控制能力,这次是循环结构。

  • Nature 要点:基于前面的示例,足以看出 Nature 可以有效应对复杂的业务流程。如果将这些流程控制从代码中移出并交由 Nature 来管理,并用配置的方式来增加控制的灵活性,将非常有利于业务的快速迭代。同时,由于代码中没有了流程控制,代码间将变得极其简洁,大幅度降低彼此之间的耦合度,这对代码的稳健性、可维护性极其有利。