羅列一下表達式所支持的屬性:
- :timeout
- :if/ unless
- :forget
- :lose
- :flank
- :on_error
- :on_cancel
- :on_timeout
- :tag
- :filter
- :take
- :discard
- :timers
- :scope
- :await
:time
下面舉個例子,如果兩個參與者過兩天之後還沒有做他們的工作,這個工作流程會提交給editor:
1 sequence do 2 participant :ref => 'author' 3 sequence :timeout => '2d' do 4 participant :ref => 'reviewer1' 5 participant :ref => 'reviewer2' 6 end 7 participant :ref => 'editor' 8 end
:time不僅能夠處理h,m,d,s(依次表示hour,minute,day,second)模式的時間定義,而且能夠處理y,M,w(分別表示year,Month,week)的模式。
就算是你給timeout傳遞一個絕對時間也沒有問題,完全能夠處理:
1 participant :ref => 'author', :timeout => 'Sun Jan 24 17:28:28 +0900 2010'
在真實的項目中,timeout的參數一般都是取自工作流程中的變量或者傳遞進來的參數。
1 participant :ref => 'author', :timeout => '${f:time_limit}'
:if/ :unless
這兩個屬性接收一個字符串的條件,如果這個字符串的值是true(或者:unless的參數的值是false),表達式就會執行,看下面的列子:
1 concurrence do 2 participant 'ceo', :if => '${f:budget} > 23000' 3 participant 'cfo' 4 participant '${f:bu_head}' 5 end
這個意思就是:如果這個工作流程中的預算配置大於23000,那麼CEO就會收到一個工作流程的任務。:if :unless條件能夠處理!=、==、=~、"is set"、"is empty"、&&、||等操作符。
:forget
當一個表達式用:forget=>true 或者:forget=>'true',獲取將要被“遺忘”的操作。被“遺忘”操作的返回值將被忽略:
1 concurrence do 2 participant 'alfred' 3 participant 'bob' 4 participant 'charly', :forget => true 5 end
charly將會收到一個工作流程,同時concurrence立即收到一個回覆。就是說在Alfred和Bob回覆了以後,concurrence就會恢復。
:lose
從來不向他的父表達式回覆,
1 Ruote.process_definition do 2 concurrence :count => 1 do 3 alfred 4 lose do 5 sequence do 6 wait '2d' 7 send_reminder_to_alfred 8 wait '2h' 9 send_alarm_to_boss 10 end 11 end 12 end 13 end
像這個列子中,reminding從來不向concurrence 回覆。concurrence在alfred回覆以後就結束了。
:flank
前面的lost中的列子可以用下面這段代碼重寫:
1 Ruote.process_definition do 2 sequence do 3 sequence :flank => true do 4 wait '2d' 5 send_reminder_to_alfred 6 wait '2h' 7 send_alarm_to_boss 8 end 9 alfred 10 end 11 end
Flanking表達式會立刻向他的父表達式返回,但是仍然可以取消,因爲Flanking表達式可以取消,所以他們的生命週期肯定不會比他的父表達式長。
1 Ruote.process_definition do 2 sequence do 3 bob :task => 'support work', :flank => true 4 alfred :task => 'main effort' 5 end 6 end
所以在這個例子中,在alfred完成他的'main effort'任務,bob的'support work'即將終止,因爲他的父表達式已經結束了。
下面概括一下forget, lose and flank的區別:
:on_error
默認情況下,在一個工作流程中發生的任何的任何錯誤都能獲取日誌和發生錯誤的地方。在過程定義的時候直接指定“on error”的行爲:
1 Ruote.define :name => 'x' do 2 3 sequence :on_error => 'handle_issue' do 4 participant 'alpha' 5 cursor do 6 # ... 7 end 8 end 9 10 define 'handle_issue' do 11 participant 'supervisor', :msg => 'process ${wfid} has gone ballistic' 12 end 13 end
如果在sequence 中發生錯誤,那麼sequence 整個分支就會取消,:on_error必須指定一個子過程或者一個參與者或者像“redo”, “undo”, “cancel”這些命令。
:on_cancel
on_cancel是用來指定一個子過程或者參與者,噹噹前過程取消的時候,設置的子過程會被調用,或者參與者收到一個工作條目。
pdef = Ruote.process_definition :name => 'aircraft carrier' do cursor :on_cancel => 'decommission' do concurrence do participant 'naval team', :task => 'operate ship' participant 'air team', :task => 'operate planes' end end define 'decommission' do concurrence do participant 'naval team', :task => 'decom weapons' participant 'air team', :task => 'decom aircrafts' end end end
上面這個過程中, “the aircraft”是一個操作,當操作取消的時候,子過程‘decommission’被觸發,裏面的naval team和air team獲取對應的任務。
和:on_error有點不一樣的是,當一個表達式在:on_cancel表達式中被取消掉的話,將不會觸發:on_cancel.例如上面的列子中“operate planes”這個活動的取消不會激活‘decommission’。只有cursor或者整個過程實例被取消的時候才能觸發‘decommission’。
:on_timeout
上面描述的了:timeout屬性。:on_time屬性是一個補充,它表示在timeout觸發的時候調用什麼子過程,或者通知某個參與者。除了子過程和參與者者,:on_timeout還可以使用‘redo’,‘error’作爲值。
1 sequence do 2 participant 'author' 3 participant 'reviewer', :timeout => '3d', :on_timeout => 'redo' 4 participant 'editor' 5 end
在這個列子中,reviewer每3天收到一個新的工作條目,直到他回覆了這個工作流程。回覆了之後將回復到editor參與者。
:tag
tag屬性用來標記一個工作過程的一個階段。
1 Ruote.process_definition do 2 sequence do 3 sequence :tag => 'phase 1' do 4 alice 5 bob 6 end 7 sequence :tag => 'phase 2' do 8 charly 9 david 10 end 11 end 12 end
例子中的tags將出現在工作流程的變量中:
p engine.process(wfid).tags.keys # => [ "phase 1" ]
:filter
Ruote2.2.0引進了一個:filter屬性。
1 Ruote.process_definition do 2 3 set 'v:f' => { 4 :in => [ 5 { :fields => '/^private_/', :remove => true } 6 ], 7 :out => [ 8 { :fields => '/^private_/', :restore => true }, 9 { :fields => '/^protected_/', :restore => true }, 10 ] 11 } 12 13 alpha 14 sequence :filter => 'f' do 15 bravo 16 charly 17 end 18 delta 19 end
在這個例子中,filter被保存在變量f中,當過程經過alpha進去sequence的時候,調用filter的in端,這個工作條目中以”private_“開始的內容被移除,接下來的bravo,charly不能夠訪問。當charly執行完成以後,調用dilter的out端的流程。
:take and :discard
:timers
這個比較好理解,下面看一個列子:
1 Ruote.define do 2 # ... 3 alice :timers => '5d: reminder, 12d: final_reminder, 15d: timeout' 4 # ... 5 end
這個例子表示爲,alice收到一個任務,她有15天來完成她,在5天以後她會收到一個提醒,在12天以後會收到一個最後一次提醒。模式爲"時間段1:action1,時間段2:action2,....,時間段3:action3"。actionx可以是一個參與者的名字,也可以是一個子過程,或者一組定義好的關鍵字。
timeout:
1 alice :timers => '1h: timeout' 2 # is equivalent to 3 alice :timeout => '1h'
error:過來給定的時間,表達式強制轉換成error
1 alice :timers => '1h: reminder, 12h: error'
在從error結束開始,到字符串的末尾或者附近的一個逗號中的字符串是錯誤信息。
undo, pass
1 alice :timers => '1h: reminder, 12h: error it went wrong'
在指定的12個小時內沒有完成工作,那麼就忽略alice了,轉交給bravo.
redo,retry
1 alice :timers => '12h: redo' 2 # which is equivalent to 3 alice :timeout => '12h', :on_timeout => 'redo'
skip,back,jump.rewind,continue,break,stop,over,reset這些命令都可以執行。
:scope
默認情況下,一個工作流程中的變量在相同的範圍,通過:scope屬性,來創建新的訪問範圍
1 define 'flow' do 2 set 'v:v' => 'alice' 3 sequence :scope => true do 4 set 'v:v' => 'bob' 5 participant '${v:x}' # will deliver to bob 6 end 7 participant '${v:x}' # will deliver to alice 8 end
例子中就是創建一個”局部“範圍來定義了set 'v:v' => 'bob'。
:await
await的引進是爲了幫助模塊的有向圖。就是等待依賴的工作完成,自己在執行。
1 concurrence do 2 sequence :tag => 'ab' do 3 a 4 b :tag => 'b' 5 end 6 sequence do 7 await :left_tag => 'ab' 8 c 9 end 10 sequence do 11 await :left_tag => 'b' 12 d 13 end 14 end
這個例子就是c要執行需要得ab執行結束之後才能執行,b執行完之後d才能執行。