hy.kim 1 year ago
parent 5aa151645f
commit 94f7bc9c4f

@ -2,11 +2,16 @@
- 산업인공지능학과 대학원 - 산업인공지능학과 대학원
2022254026 2022254026
김홍열 김홍열
### Durable Rules 란? ### Durable Rules 란?
* 비즈니스 룰 엔진을 구현하기 위한 라이브러리로 python, ruby, nodejs로 구현할 수 있다. * 비즈니스 룰 엔진을 구현하기 위한 라이브러리로 python, ruby, nodejs로 구현할 수 있다.
### Durable Rules 설치하기 (Python) ### Durable Rules 설치하기 (Python)
``` plantext
``` planetext
pip install durable_rules pip install durable_rules
``` ```
### Durable Rules Git ### Durable Rules Git
[github - jruizgit/rules](https://github.com/jruizgit/rules) [github - jruizgit/rules](https://github.com/jruizgit/rules)
@ -17,8 +22,11 @@ pip install durable_rules
<div markdown="1"> <div markdown="1">
##### 패키지 불러오기 ##### 패키지 불러오기
```
``` planetext
from durable.lang import * from durable.lang import *
``` ```
# Basic # Basic
@ -30,7 +38,9 @@ from durable.lang import *
* 규칙은 프레임워크의 기본 구성 요소입니다. * 규칙은 프레임워크의 기본 구성 요소입니다.
* 규칙의 선행 조건은 규칙의 결과 조건(동작)을 실행하기 위해 충족되어야 하는 조건을 정의합니다. * 규칙의 선행 조건은 규칙의 결과 조건(동작)을 실행하기 위해 충족되어야 하는 조건을 정의합니다.
* 관례적으로 m은 주어진 규칙에 의해 평가될 데이터를 나타냅니다. * 관례적으로 m은 주어진 규칙에 의해 평가될 데이터를 나타냅니다.
``` python ``` python
with ruleset('test'): with ruleset('test'):
# antecedent # antecedent
@when_all(m.subject == 'World') @when_all(m.subject == 'World')
@ -38,10 +48,12 @@ with ruleset('test'):
# consequent # consequent
print ('Hello {0}'.format(c.m.subject)) print ('Hello {0}'.format(c.m.subject))
post('test', { 'subject': 'World' }) post('test', { 'subject': 'World' })
``` ```
</div> </div>
</details> </details>
<details> <details>
<summary>Facts (assert_fact)</summary> <summary>Facts (assert_fact)</summary>
<div markdown="1"> <div markdown="1">
@ -49,7 +61,9 @@ post('test', { 'subject': 'World' })
* 사실은 지식 기반을 정의하는 데이터를 나타냅니다. * 사실은 지식 기반을 정의하는 데이터를 나타냅니다.
* 사실은 JSON 객체로 주장되며, 취소될 때까지 저장됩니다. * 사실은 JSON 객체로 주장되며, 취소될 때까지 저장됩니다.
* 사실이 규칙의 선행 조건을 만족하면, 규칙의 결과 조건이 실행됩니다. * 사실이 규칙의 선행 조건을 만족하면, 규칙의 결과 조건이 실행됩니다.
``` python ``` python
with ruleset('animal'): with ruleset('animal'):
# will be triggered by 'Kermit eats flies' # will be triggered by 'Kermit eats flies'
@when_all((m.predicate == 'eats') & (m.object == 'flies')) @when_all((m.predicate == 'eats') & (m.object == 'flies'))
@ -73,10 +87,12 @@ with ruleset('animal'):
def output(c): def output(c):
print('Fact: {0} {1} {2}'.format(c.m.subject, c.m.predicate, c.m.object)) print('Fact: {0} {1} {2}'.format(c.m.subject, c.m.predicate, c.m.object))
assert_fact('animal', { 'subject': 'Kermit', 'predicate': 'eats', 'object': 'flies' }) assert_fact('animal', { 'subject': 'Kermit', 'predicate': 'eats', 'object': 'flies' })
``` ```
</div> </div>
</details> </details>
<details> <details>
<summary>Events (post)</summary> <summary>Events (post)</summary>
<div markdown="1"> <div markdown="1">
@ -85,7 +101,9 @@ assert_fact('animal', { 'subject': 'Kermit', 'predicate': 'eats', 'object': 'fli
* 이벤트란 일시적인 사실로, 결과를 실행하기 직전에 취소되는 사실입니다. * 이벤트란 일시적인 사실로, 결과를 실행하기 직전에 취소되는 사실입니다.
* 따라서 이벤트는 한 번만 관찰할 수 있습니다. * 따라서 이벤트는 한 번만 관찰할 수 있습니다.
* 이벤트는 관찰될 때까지 저장됩니다. * 이벤트는 관찰될 때까지 저장됩니다.
``` python ``` python
with ruleset('risk'): with ruleset('risk'):
@when_all(c.first << m.t == 'purchase', @when_all(c.first << m.t == 'purchase',
c.second << m.location != c.first.location) c.second << m.location != c.first.location)
@ -94,15 +112,23 @@ with ruleset('risk'):
print('Fraud detected -> {0}, {1}'.format(c.first.location, c.second.location)) print('Fraud detected -> {0}, {1}'.format(c.first.location, c.second.location))
post('risk', {'t': 'purchase', 'location': 'US'}) post('risk', {'t': 'purchase', 'location': 'US'})
post('risk', {'t': 'purchase', 'location': 'CA'}) post('risk', {'t': 'purchase', 'location': 'CA'})
``` ```
##### ✨위 예제에서 Event가 아닌 Fact를 적용하면 다음과 같이 출력됩니다. ##### ✨위 예제에서 Event가 아닌 Fact를 적용하면 다음과 같이 출력됩니다.
``` python ``` python
assert_fact('risk', {'t': 'purchase', 'location': 'US', 'last_location': None}) assert_fact('risk', {'t': 'purchase', 'location': 'US', 'last_location': None})
assert_fact('risk', {'t': 'purchase', 'location': 'CA', 'last_location': None}) assert_fact('risk', {'t': 'purchase', 'location': 'CA', 'last_location': None})
``` ```
``` plaintext ``` plaintext
Fraud detected -> US, CA Fraud detected -> US, CA
Fraud detected -> CA, US Fraud detected -> CA, US
``` ```
예에서 두 가지 사실 모두 첫 번째 조건인 m.t == 'purchase'를 충족하며, 각 사실은 첫 번째 조건을 충족한 사실과 관련하여 두 번째 조건인 m.location != c.first.location을 충족합니다. 예에서 두 가지 사실 모두 첫 번째 조건인 m.t == 'purchase'를 충족하며, 각 사실은 첫 번째 조건을 충족한 사실과 관련하여 두 번째 조건인 m.location != c.first.location을 충족합니다.
@ -112,6 +138,7 @@ Fraud detected -> CA, US
</div> </div>
</details> </details>
<details> <details>
<summary>State (s, update_state)</summary> <summary>State (s, update_state)</summary>
<div markdown="1"> <div markdown="1">
@ -121,7 +148,9 @@ Fraud detected -> CA, US
* 컨텍스트 상태는 삭제될 때까지 저장됩니다. * 컨텍스트 상태는 삭제될 때까지 저장됩니다.
* 컨텍스트 상태 변경은 규칙에 의해 평가될 수 있습니다. * 컨텍스트 상태 변경은 규칙에 의해 평가될 수 있습니다.
* 관례적으로 s는 규칙에 의해 평가되는 상태를 나타냅니다. * 관례적으로 s는 규칙에 의해 평가되는 상태를 나타냅니다.
``` python ``` python
with ruleset('flow'): with ruleset('flow'):
# state condition uses 's' # state condition uses 's'
@when_all(s.status == 'start') @when_all(s.status == 'start')
@ -142,17 +171,21 @@ with ruleset('flow'):
# deletes state at the end # deletes state at the end
c.delete_state() c.delete_state()
update_state('flow', { 'status': 'start' }) update_state('flow', { 'status': 'start' })
``` ```
</div> </div>
</details> </details>
<details> <details>
<summary>Identity (+속성, none(+속성))</summary> <summary>Identity (+속성, none(+속성))</summary>
<div markdown="1"> <div markdown="1">
* 같은 속성 이름과 값이 있는 팩트들은 단언(asserted)되거나 철회(retracted)될 때 동등하다고 간주됩니다. * 같은 속성 이름과 값이 있는 팩트들은 단언(asserted)되거나 철회(retracted)될 때 동등하다고 간주됩니다.
* 같은 속성 이름과 값이 있는 이벤트들은 게시 시간이 중요하기 때문에 게시될 때 서로 다른 것으로 간주됩니다. * 같은 속성 이름과 값이 있는 이벤트들은 게시 시간이 중요하기 때문에 게시될 때 서로 다른 것으로 간주됩니다.
``` python ``` python
with ruleset('bookstore'): with ruleset('bookstore'):
# this rule will trigger for events with status # this rule will trigger for events with status
@when_all(+m.status) @when_all(+m.status)
@ -168,9 +201,10 @@ with ruleset('bookstore'):
def empty(c): def empty(c):
print('bookstore-> No books') print('bookstore-> No books')
``` ```
``` python ``` python
# 단언(assert_fact)이 성공했기 때문에 예외를 발생시키지 않습니다.
# 단언(assert_fact)이 성공했기 때문에 예외를 발생시키지 않습니다.
assert_fact('bookstore', { assert_fact('bookstore', {
'name': 'The new book', 'name': 'The new book',
'seller': 'bookstore', 'seller': 'bookstore',
@ -179,7 +213,6 @@ assert_fact('bookstore', {
}) })
# 이미 단언(assert_fact)된 사실이기 때문에 MessageObservedError가 발생합니다. # 이미 단언(assert_fact)된 사실이기 때문에 MessageObservedError가 발생합니다.
try: try:
assert_fact('bookstore', { assert_fact('bookstore', {
'reference': '75323', 'reference': '75323',
@ -191,14 +224,12 @@ except BaseException as e:
print('bookstore expected {0}'.format(e.message)) print('bookstore expected {0}'.format(e.message))
# 새로운 이벤트가 게시되기 때문에 예외를 발생시키지 않습니다. # 새로운 이벤트가 게시되기 때문에 예외를 발생시키지 않습니다.
post('bookstore', { post('bookstore', {
'reference': '75323', 'reference': '75323',
'status': 'Active' 'status': 'Active'
}) })
# 새로운 이벤트가 게시되기 때문에 예외를 발생시키지 않습니다. # 새로운 이벤트가 게시되기 때문에 예외를 발생시키지 않습니다.
post('bookstore', { post('bookstore', {
'reference': '75323', 'reference': '75323',
'status': 'Active' 'status': 'Active'
@ -210,10 +241,12 @@ retract_fact('bookstore', {
'price': 500, 'price': 500,
'seller': 'bookstore' 'seller': 'bookstore'
}) })
``` ```
</div> </div>
</details> </details>
<details> <details>
<summary>Correlated Sequence</summary> <summary>Correlated Sequence</summary>
<div markdown="1"> <div markdown="1">
@ -222,7 +255,9 @@ retract_fact('bookstore', {
* 기본적으로 관련된 시퀀스는 서로 다른 메시지를 캡처합니다. 아래 예시에서 두 번째 이벤트는 두 번째와 세 번째 조건을 모두 만족하지만, 이벤트는 두 번째 조건에 대해서만 캡처됩니다. distinct 속성을 사용하여 서로 다른 이벤트 또는 사실의 상관 관계를 비활성화할 수 있습니다. * 기본적으로 관련된 시퀀스는 서로 다른 메시지를 캡처합니다. 아래 예시에서 두 번째 이벤트는 두 번째와 세 번째 조건을 모두 만족하지만, 이벤트는 두 번째 조건에 대해서만 캡처됩니다. distinct 속성을 사용하여 서로 다른 이벤트 또는 사실의 상관 관계를 비활성화할 수 있습니다.
* when_all 주석은 이벤트 또는 사실의 시퀀스를 표현합니다. << 연산자는 이후 표현식에서 참조할 수 있는 이벤트 또는 사실의 이름을 지정하는 데 사용됩니다. 이벤트 또는 사실을 참조할 때 모든 속성을 사용할 수 있습니다. 산술 연산자를 사용하여 복잡한 패턴을 표현할 수 있습니다. * when_all 주석은 이벤트 또는 사실의 시퀀스를 표현합니다. << 연산자는 이후 표현식에서 참조할 수 있는 이벤트 또는 사실의 이름을 지정하는 데 사용됩니다. 이벤트 또는 사실을 참조할 때 모든 속성을 사용할 수 있습니다. 산술 연산자를 사용하여 복잡한 패턴을 표현할 수 있습니다.
* 산술 연산자: +, -, *, / * 산술 연산자: +, -, *, /
``` python ``` python
from durable.lang import * from durable.lang import *
with ruleset('risk'): with ruleset('risk'):
@ -238,10 +273,12 @@ with ruleset('risk'):
post('risk', { 'amount': 50 }) post('risk', { 'amount': 50 })
post('risk', { 'amount': 200 }) post('risk', { 'amount': 200 })
post('risk', { 'amount': 251 }) post('risk', { 'amount': 251 })
``` ```
</div> </div>
</details> </details>
<details> <details>
<summary>Choice of Sequences</summary> <summary>Choice of Sequences</summary>
<div markdown="1"> <div markdown="1">
@ -253,7 +290,9 @@ post('risk', { 'amount': 251 })
all: 이벤트 또는 사실 패턴의 집합입니다. 동작을 실행하려면 모든 패턴이 일치해야 합니다. all: 이벤트 또는 사실 패턴의 집합입니다. 동작을 실행하려면 모든 패턴이 일치해야 합니다.
any: 이벤트 또는 사실 패턴의 집합입니다. 어느 하나만 일치해도 동작이 실행됩니다. any: 이벤트 또는 사실 패턴의 집합입니다. 어느 하나만 일치해도 동작이 실행됩니다.
``` python ``` python
from durable.lang import * from durable.lang import *
with ruleset('expense'): with ruleset('expense'):
@ -272,10 +311,12 @@ post('expense', { 'subject': 'approve' })
post('expense', { 'amount': 1000 }) post('expense', { 'amount': 1000 })
post('expense', { 'subject': 'jumbo' }) post('expense', { 'subject': 'jumbo' })
post('expense', { 'amount': 10000 }) post('expense', { 'amount': 10000 })
``` ```
</div> </div>
</details> </details>
<details> <details>
<summary>Lack of Information</summary> <summary>Lack of Information</summary>
<div markdown="1"> <div markdown="1">
@ -283,7 +324,9 @@ post('expense', { 'amount': 10000 })
* 일부 경우에는 정보 부족이 중요한 의미를 가집니다. none 함수는 관련된 시퀀스가 있는 규칙에서 정보 부족을 평가하는 데 사용할 수 있습니다. * 일부 경우에는 정보 부족이 중요한 의미를 가집니다. none 함수는 관련된 시퀀스가 있는 규칙에서 정보 부족을 평가하는 데 사용할 수 있습니다.
* 참고: none 함수는 정보 부족에 대한 추론을 위해 정보가 필요합니다. 즉, 해당 규칙에 이벤트나 사실이 등록되지 않은 경우에는 동작을 실행하지 않습니다. * 참고: none 함수는 정보 부족에 대한 추론을 위해 정보가 필요합니다. 즉, 해당 규칙에 이벤트나 사실이 등록되지 않은 경우에는 동작을 실행하지 않습니다.
``` python ``` python
from durable.lang import * from durable.lang import *
with ruleset('risk'): with ruleset('risk'):
@ -303,17 +346,21 @@ assert_fact('risk', { 'sid': 1, 't': 'deposit' })
assert_fact('risk', { 'sid': 1, 't': 'withdrawal' }) assert_fact('risk', { 'sid': 1, 't': 'withdrawal' })
assert_fact('risk', { 'sid': 1, 't': 'chargeback' }) assert_fact('risk', { 'sid': 1, 't': 'chargeback' })
retract_fact('risk', { 'sid': 1, 't': 'balance' }) retract_fact('risk', { 'sid': 1, 't': 'balance' })
``` ```
</div> </div>
</details> </details>
<details> <details>
<summary>Nested Objects</summary> <summary>Nested Objects</summary>
<div markdown="1"> <div markdown="1">
* 중첩된 이벤트 또는 사실에 대한 질의도 지원됩니다. * 중첩된 이벤트 또는 사실에 대한 질의도 지원됩니다.
* . 표기법은 중첩된 객체의 속성에 대한 조건을 정의하는 데 사용됩니다. * . 표기법은 중첩된 객체의 속성에 대한 조건을 정의하는 데 사용됩니다.
``` python ``` python
from durable.lang import * from durable.lang import *
with ruleset('expense'): with ruleset('expense'):
@ -323,21 +370,28 @@ with ruleset('expense'):
def approved(c): def approved(c):
print ('bill amount ->{0}'.format(c.bill.invoice.amount)) print ('bill amount ->{0}'.format(c.bill.invoice.amount))
print ('account payment amount ->{0}'.format(c.account.payment.invoice.amount)) print ('account payment amount ->{0}'.format(c.account.payment.invoice.amount))
``` ```
``` python ``` python
# one level of nesting # one level of nesting
post('expense', {'t': 'bill', 'invoice': {'amount': 100}}) post('expense', {'t': 'bill', 'invoice': {'amount': 100}})
# two levels of nesting # two levels of nesting
post('expense', {'t': 'account', 'payment': {'invoice': {'amount': 100}}}) post('expense', {'t': 'account', 'payment': {'invoice': {'amount': 100}}})
``` ```
</div> </div>
</details> </details>
<details> <details>
<summary>Arrays</summary> <summary>Arrays</summary>
<div markdown="1"> <div markdown="1">
``` python ``` python
from durable.lang import * from durable.lang import *
with ruleset('risk'): with ruleset('risk'):
@ -365,16 +419,20 @@ post('risk', {'payments': [ 150, 300, 450 ]})
post('risk', {'payments': [ { 'amount' : 200 }, { 'amount' : 300 }, { 'amount' : 450 } ]}) post('risk', {'payments': [ { 'amount' : 200 }, { 'amount' : 300 }, { 'amount' : 450 } ]})
post('risk', {'cards': [ 'one card', 'two cards', 'three cards' ]}) post('risk', {'cards': [ 'one card', 'two cards', 'three cards' ]})
post('risk', {'payments': [ [ 10, 20, 30 ], [ 30, 40, 50 ], [ 10, 20 ] ]}) post('risk', {'payments': [ [ 10, 20, 30 ], [ 30, 40, 50 ], [ 10, 20 ] ]})
``` ```
</div> </div>
</details> </details>
<details> <details>
<summary>Facts and Events as rvalues</summary> <summary>Facts and Events as rvalues</summary>
<div markdown="1"> <div markdown="1">
* 스칼라 값(문자열, 숫자 및 부울 값) 외에도 표현식의 오른쪽에서 관찰된 사실이나 이벤트를 사용할 수 있습니다. * 스칼라 값(문자열, 숫자 및 부울 값) 외에도 표현식의 오른쪽에서 관찰된 사실이나 이벤트를 사용할 수 있습니다.
``` python ``` python
from durable.lang import * from durable.lang import *
with ruleset('risk'): with ruleset('risk'):
@ -394,6 +452,7 @@ post('risk', { 'debit': 220, 'credit': 100 })
post('risk', { 'debit': 150, 'credit': 100 }) post('risk', { 'debit': 150, 'credit': 100 })
post('risk', { 'amount': 200 }) post('risk', { 'amount': 200 })
post('risk', { 'amount': 500 }) post('risk', { 'amount': 500 })
``` ```
</div> </div>
@ -408,7 +467,9 @@ post('risk', { 'amount': 500 })
* 이벤트와 사실 평가는 여러 결과를 초래할 수 있습니다. pri (중요도) 함수를 사용하여 트리거 순서를 제어할 수 있습니다. 낮은 값의 작업이 먼저 실행됩니다. 모든 작업의 기본값은 0입니다. * 이벤트와 사실 평가는 여러 결과를 초래할 수 있습니다. pri (중요도) 함수를 사용하여 트리거 순서를 제어할 수 있습니다. 낮은 값의 작업이 먼저 실행됩니다. 모든 작업의 기본값은 0입니다.
* 이 예시에서, 마지막 규칙이 가장 높은 우선순위를 가지고 있으므로 먼저 트리거됩니다. * 이 예시에서, 마지막 규칙이 가장 높은 우선순위를 가지고 있으므로 먼저 트리거됩니다.
``` python ``` python
from durable.lang import * from durable.lang import *
with ruleset('attributes'): with ruleset('attributes'):
@ -427,10 +488,12 @@ with ruleset('attributes'):
assert_fact('attributes', { 'amount': 50 }) assert_fact('attributes', { 'amount': 50 })
assert_fact('attributes', { 'amount': 150 }) assert_fact('attributes', { 'amount': 150 })
assert_fact('attributes', { 'amount': 250 }) assert_fact('attributes', { 'amount': 250 })
``` ```
</div> </div>
</details> </details>
<details> <details>
<summary>Action Batches</summary> <summary>Action Batches</summary>
<div markdown="1"> <div markdown="1">
@ -442,7 +505,9 @@ count: 동작을 예약하기 전에 규칙이 만족해야 하는 정확한 횟
cap: 동작을 예약하기 전에 규칙이 만족해야 하는 최대 횟수를 정의합니다. cap: 동작을 예약하기 전에 규칙이 만족해야 하는 최대 횟수를 정의합니다.
* 이 예시는 정확히 세 개의 승인을 일괄 처리하고 거절 수를 두 개로 제한합니다: * 이 예시는 정확히 세 개의 승인을 일괄 처리하고 거절 수를 두 개로 제한합니다:
``` python ``` python
from durable.lang import * from durable.lang import *
with ruleset('expense'): with ruleset('expense'):
@ -465,10 +530,12 @@ post_batch('expense', [{ 'amount': 10 },
{ 'amount': 200 }, { 'amount': 200 },
{ 'amount': 400 }]) { 'amount': 400 }])
assert_fact('expense', { 'review': True }) assert_fact('expense', { 'review': True })
``` ```
</div> </div>
</details> </details>
<details> <details>
<summary>Async Actions</summary> <summary>Async Actions</summary>
<div markdown="1"> <div markdown="1">
@ -477,7 +544,9 @@ assert_fact('expense', { 'review': True })
* 동작이 완료되면 완료(complete) 함수를 호출해야 합니다. * 동작이 완료되면 완료(complete) 함수를 호출해야 합니다.
* 기본적으로 동작은 5초 후에 포기된 것으로 간주됩니다. * 기본적으로 동작은 5초 후에 포기된 것으로 간주됩니다.
* 이 값은 작업 함수에서 다른 숫자를 반환하거나 renew_action_lease를 호출함으로써 변경할 수 있습니다. * 이 값은 작업 함수에서 다른 숫자를 반환하거나 renew_action_lease를 호출함으로써 변경할 수 있습니다.
``` python ``` python
from durable.lang import * from durable.lang import *
import threading import threading
@ -517,17 +586,21 @@ with ruleset('flow'):
return 10 return 10
update_state('flow', { 'state': 'first' }) update_state('flow', { 'state': 'first' })
``` ```
</div> </div>
</details> </details>
<details> <details>
<summary>Unhandled Exceptions</summary> <summary>Unhandled Exceptions</summary>
<div markdown="1"> <div markdown="1">
* 액션에서 예외가 처리되지 않은 경우, 예외는 컨텍스트 상태에 저장됩니다. * 액션에서 예외가 처리되지 않은 경우, 예외는 컨텍스트 상태에 저장됩니다.
* 이를 통해 예외 처리 규칙을 작성할 수 있습니다. * 이를 통해 예외 처리 규칙을 작성할 수 있습니다.
``` python ``` python
from durable.lang import * from durable.lang import *
with ruleset('flow'): with ruleset('flow'):
@ -543,6 +616,7 @@ with ruleset('flow'):
c.s.exception = None c.s.exception = None
post('flow', { 'action': 'start' }) post('flow', { 'action': 'start' })
``` ```
</div> </div>
</details> </details>
@ -565,7 +639,9 @@ post('flow', { 'action': 'start' })
6. 트리거에는 목적지 상태가 있습니다. 6. 트리거에는 목적지 상태가 있습니다.
7. 트리거는 규칙을 가질 수 있습니다 (부재는 상태 진입을 의미). 7. 트리거는 규칙을 가질 수 있습니다 (부재는 상태 진입을 의미).
8. 트리거는 액션을 가질 수 있습니다. 8. 트리거는 액션을 가질 수 있습니다.
``` python ``` python
from durable.lang import * from durable.lang import *
with statechart('expense'): with statechart('expense'):
@ -609,10 +685,12 @@ post('expense', { 'sid': 1, 'subject': 'denied' })
# events directed to statechart instance with id '2' # events directed to statechart instance with id '2'
post('expense', { 'sid': 2, 'subject': 'approve', 'amount': 10000 }) post('expense', { 'sid': 2, 'subject': 'approve', 'amount': 10000 })
``` ```
</div> </div>
</details> </details>
<details> <details>
<summary>Nested States</summary> <summary>Nested States</summary>
<div markdown="1"> <div markdown="1">
@ -620,7 +698,9 @@ post('expense', { 'sid': 2, 'subject': 'approve', 'amount': 10000 })
* 중첩 상태를 사용하면 컴팩트한 상태도를 작성할 수 있습니다. * 중첩 상태를 사용하면 컴팩트한 상태도를 작성할 수 있습니다.
* 컨텍스트가 중첩 상태에 있는 경우, 컨텍스트는 묵시적으로 주변 상태에도 있습니다. * 컨텍스트가 중첩 상태에 있는 경우, 컨텍스트는 묵시적으로 주변 상태에도 있습니다.
* 상태도는 하위 상태 컨텍스트에서 모든 이벤트를 처리하려고 시도합니다. * 하위 상태가 이벤트를 처리하지 않으면, 이벤트는 자동으로 상위 상태 컨텍스트에서 처리됩니다. * 상태도는 하위 상태 컨텍스트에서 모든 이벤트를 처리하려고 시도합니다. * 하위 상태가 이벤트를 처리하지 않으면, 이벤트는 자동으로 상위 상태 컨텍스트에서 처리됩니다.
``` python ``` python
from durable.lang import * from durable.lang import *
with statechart('worker'): with statechart('worker'):
@ -656,10 +736,12 @@ post('worker', { 'subject': 'continue' })
# will move the statechart out of the work state # will move the statechart out of the work state
post('worker', { 'subject': 'cancel' }) post('worker', { 'subject': 'cancel' })
``` ```
</div> </div>
</details> </details>
<details> <details>
<summary>Flowchart</summary> <summary>Flowchart</summary>
<div markdown="1"> <div markdown="1">
@ -674,7 +756,9 @@ post('worker', { 'subject': 'cancel' })
4. 단계는 액션을 가질 수 있습니다. 4. 단계는 액션을 가질 수 있습니다.
5. 단계는 0개 이상의 조건을 가질 수 있습니다. 5. 단계는 0개 이상의 조건을 가질 수 있습니다.
6. 조건에는 규칙과 목적지 단계가 있습니다. 6. 조건에는 규칙과 목적지 단계가 있습니다.
``` python ``` python
from durable.lang import * from durable.lang import *
with flowchart('expense'): with flowchart('expense'):
@ -703,8 +787,11 @@ with flowchart('expense'):
@run @run
def denied(c): def denied(c):
print('expense denied') print('expense denied')
``` ```
``` python ``` python
# events for the default flowchart instance, approved after retry # events for the default flowchart instance, approved after retry
post('expense', { 'subject': 'approve', 'amount': 100 }) post('expense', { 'subject': 'approve', 'amount': 100 })
# post('expense', { 'subject': 'retry' }) # post('expense', { 'subject': 'retry' })
@ -716,10 +803,12 @@ post('expense', { 'subject': 'approve', 'amount': 100 })
# # # event for the flowchart instance '2' immediately denied # # # event for the flowchart instance '2' immediately denied
# post('expense', { 'sid': 2, 'subject': 'approve', 'amount': 10000}) # post('expense', { 'sid': 2, 'subject': 'approve', 'amount': 10000})
``` ```
</div> </div>
</details> </details>
<details> <details>
<summary>Timer</summary> <summary>Timer</summary>
<div markdown="1"> <div markdown="1">
@ -728,14 +817,19 @@ post('expense', { 'subject': 'approve', 'amount': 100 })
* 시간 초과 조건은 규칙 전제에 포함될 수 있습니다. * 시간 초과 조건은 규칙 전제에 포함될 수 있습니다.
* 기본적으로 타임아웃은 이벤트로 트리거됩니다 (한 번만 관찰됨). * 기본적으로 타임아웃은 이벤트로 트리거됩니다 (한 번만 관찰됨).
* '수동 리셋' 타이머에 의해 타임아웃은 사실로도 트리거될 수 있으며, 액션 실행 중 타이머를 리셋할 수 있습니다 (마지막 예제 참조). * '수동 리셋' 타이머에 의해 타임아웃은 사실로도 트리거될 수 있으며, 액션 실행 중 타이머를 리셋할 수 있습니다 (마지막 예제 참조).
```
``` planetext
start_timer: 지정된 이름과 지속 시간으로 타이머를 시작합니다 (manual_reset은 선택 사항입니다). start_timer: 지정된 이름과 지속 시간으로 타이머를 시작합니다 (manual_reset은 선택 사항입니다).
reset_timer: '수동 리셋' 타이머를 리셋합니다. reset_timer: '수동 리셋' 타이머를 리셋합니다.
cancel_timer: 진행 중인 타이머를 취소합니다. cancel_timer: 진행 중인 타이머를 취소합니다.
timeout: 전제 조건으로 사용됩니다. timeout: 전제 조건으로 사용됩니다.
from durable.lang import * from durable.lang import *
``` ```
``` python ``` python
with ruleset('timer'): with ruleset('timer'):
@when_all(m.subject == 'start') @when_all(m.subject == 'start')
@ -747,9 +841,13 @@ with ruleset('timer'):
print('timer timeout') print('timer timeout')
post('timer', { 'subject': 'start' }) post('timer', { 'subject': 'start' })
``` ```
* 아래 예제에서는 타이머를 사용하여 더 높은 이벤트 비율을 감지합니다. * 아래 예제에서는 타이머를 사용하여 더 높은 이벤트 비율을 감지합니다.
``` python ``` python
from durable.lang import * from durable.lang import *
with statechart('risk'): with statechart('risk'):
@ -772,8 +870,11 @@ with statechart('risk'):
state('fraud') state('fraud')
state('exit') state('exit')
``` ```
``` python ``` python
# three events in a row will trigger the fraud rule # three events in a row will trigger the fraud rule
post('risk', { 'amount': 200 }) post('risk', { 'amount': 200 })
post('risk', { 'amount': 300 }) post('risk', { 'amount': 300 })
@ -782,10 +883,13 @@ post('risk', { 'amount': 400 })
# two events will exit after 5 seconds # two events will exit after 5 seconds
post('risk', { 'sid': 1, 'amount': 500 }) post('risk', { 'sid': 1, 'amount': 500 })
post('risk', { 'sid': 1, 'amount': 600 }) post('risk', { 'sid': 1, 'amount': 600 })
``` ```
* 이 예제에서는 속도를 측정하기 위해 수동 리셋 타이머를 사용합니다. * 이 예제에서는 속도를 측정하기 위해 수동 리셋 타이머를 사용합니다.
``` python ``` python
from durable.lang import * from durable.lang import *
with statechart('risk'): with statechart('risk'):
@ -811,17 +915,21 @@ with statechart('risk'):
print('velocity: no events in 5 seconds') print('velocity: no events in 5 seconds')
c.reset_timer('VelocityTimer') c.reset_timer('VelocityTimer')
c.start_timer('VelocityTimer', 5, True) c.start_timer('VelocityTimer', 5, True)
```
``` ```
``` planetext
post('risk', { 'amount': 200 }) post('risk', { 'amount': 200 })
post('risk', { 'amount': 300 }) post('risk', { 'amount': 300 })
post('risk', { 'amount': 50 }) post('risk', { 'amount': 50 })
post('risk', { 'amount': 500 }) post('risk', { 'amount': 500 })
post('risk', { 'amount': 600 }) post('risk', { 'amount': 600 })
``` ```
</div> </div>
</details> </details>
</div> </div>
</details> </details>
Loading…
Cancel
Save