Class: Ruote::ProcessStatus
- Inherits:
-
Object
- Object
- Ruote::ProcessStatus
- Defined in:
- lib/ruote/dboard/process_status.rb
Overview
A ‘view’ on the status of a process instance.
Returned by the #process and the #processes methods of Ruote::Dashboard.
Instance Attribute Summary collapse
-
#errors ⇒ Object
readonly
An array of errors currently plaguing the process instance.
-
#expressions ⇒ Object
readonly
The expressions that compose the process instance.
-
#root_expression ⇒ Object
readonly
Returns the expression at the root of the process instance.
-
#schedules ⇒ Object
readonly
An array of schedules (open structs yielding information about the schedules of this process).
-
#stored_workitems ⇒ Object
readonly
An array of the workitems currently in the storage participant for this process instance.
-
#trackers ⇒ Object
readonly
TODO.
Class Method Summary collapse
-
.fetch(context, wfids, opts) ⇒ Object
Used by Ruote::Dashboard#process and #processes.
Instance Method Summary collapse
-
#all_tags ⇒ Object
Returns a hash tagname => array of feis of all the tags set in the process instance.
-
#all_variables ⇒ Object
Returns a hash fei => variable_hash containing all the variable bindings (expression by expression) of the process instance.
-
#current_tree ⇒ Object
Returns the current version of the process definition tree.
-
#definition_name ⇒ Object
For a process.
-
#definition_revision ⇒ Object
For a process.
- #hinspect(indent, h) ⇒ Object
-
#initialize(context, expressions, sworkitems, errors, schedules, trackers) ⇒ ProcessStatus
constructor
Called by Ruote::Dashboard#processes or Ruote::Dashboard#process.
- #inspect ⇒ Object
-
#last_active ⇒ Object
Returns a parseable UTC datetime string which indicates when the process was last active.
-
#launched_time ⇒ Object
Returns a Time instance indicating when the process instance was launched.
-
#leaves ⇒ Object
Returns the expressions where the flow is currently, ak the leaves of the execution tree.
-
#original_tree ⇒ Object
Returns the process definition tree as it was when this process instance was launched.
-
#past_tags ⇒ Object
Returns the list of “past tags”, tags that have been entered and left.
-
#position ⇒ Object
Returns the ‘position’ of the process.
-
#root_expression_for(fei) ⇒ Object
Given an expression id, returns the root (top ancestor) for its expression.
-
#root_expressions ⇒ Object
Returns a list of all the expressions that have no parent expression.
-
#root_workitem ⇒ Object
Returns the workitem as was applied at the root expression.
-
#tags ⇒ Object
Returns a hash tagname => fei of tags set at the root of the process instance.
-
#to_dot(opts = {}) ⇒ Object
Returns a ‘dot’ representation of the process.
-
#to_h ⇒ Object
Outputs the process status as a hash (easily JSONifiable).
- #to_s ⇒ Object
-
#variables ⇒ Object
Returns the process variables set for this process instance.
-
#wfid ⇒ Object
Returns the unique identifier for this process instance.
-
#workitems ⇒ Object
Returns a list of the workitems currently ‘out’ to participants.
Constructor Details
#initialize(context, expressions, sworkitems, errors, schedules, trackers) ⇒ ProcessStatus
Called by Ruote::Dashboard#processes or Ruote::Dashboard#process.
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/ruote/dboard/process_status.rb', line 69 def initialize(context, expressions, sworkitems, errors, schedules, trackers) # # preparing data @expressions = expressions.collect { |e| Ruote::Exp::FlowExpression.from_h(context, e) }.sort_by { |e| e.fei.expid } @stored_workitems = sworkitems.map { |h| Ruote::Workitem.new(h) } @errors = errors.sort! { |a, b| a.fei.expid <=> b.fei.expid } @schedules = schedules.sort! { |a, b| a['owner'].sid <=> b['owner'].sid } @root_expression = root_expressions.first # # linking errors and expressions for easy navigation @errors.each do |err| err.flow_expression = @expressions.find { |fexp| fexp.fei == err.fei } err.flow_expression.error = err if err.flow_expression end @trackers = trackers end |
Instance Attribute Details
#errors ⇒ Object (readonly)
An array of errors currently plaguing the process instance. Hopefully, this array is empty.
56 57 58 |
# File 'lib/ruote/dboard/process_status.rb', line 56 def errors @errors end |
#expressions ⇒ Object (readonly)
The expressions that compose the process instance.
40 41 42 |
# File 'lib/ruote/dboard/process_status.rb', line 40 def expressions @expressions end |
#root_expression ⇒ Object (readonly)
Returns the expression at the root of the process instance.
44 45 46 |
# File 'lib/ruote/dboard/process_status.rb', line 44 def root_expression @root_expression end |
#schedules ⇒ Object (readonly)
An array of schedules (open structs yielding information about the schedules of this process)
61 62 63 |
# File 'lib/ruote/dboard/process_status.rb', line 61 def schedules @schedules end |
#stored_workitems ⇒ Object (readonly)
An array of the workitems currently in the storage participant for this process instance.
Do not confuse with #workitems
51 52 53 |
# File 'lib/ruote/dboard/process_status.rb', line 51 def stored_workitems @stored_workitems end |
#trackers ⇒ Object (readonly)
TODO
65 66 67 |
# File 'lib/ruote/dboard/process_status.rb', line 65 def trackers @trackers end |
Class Method Details
.fetch(context, wfids, opts) ⇒ Object
Used by Ruote::Dashboard#process and #processes
527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 |
# File 'lib/ruote/dboard/process_status.rb', line 527 def self.fetch(context, wfids, opts) swfids = wfids.collect { |wfid| /!#{wfid}-\d+$/ } batch = { 'id' => "#{Thread.current.object_id}-#{Time.now.to_f}" } # # some storages may optimize when they can distinguish # which get_many fit in the same batch... exps = context.storage.get_many( 'expressions', wfids, :batch => batch).compact swis = context.storage.get_many( 'workitems', wfids, :batch => batch).compact errs = context.storage.get_many( 'errors', wfids, :batch => batch).compact schs = context.storage.get_many( 'schedules', swfids, :batch => batch).compact # # some slow storages need the compaction... couch... errs = errs.collect { |err| ProcessError.new(err) } schs = schs.collect { |sch| Ruote.schedule_to_h(sch) } by_wfid = {} as = lambda { [ [], [], [], [], [] ] } exps.each { |exp| (by_wfid[exp['fei']['wfid']] ||= as.call)[0] << exp } swis.each { |swi| (by_wfid[swi['fei']['wfid']] ||= as.call)[1] << swi } errs.each { |err| (by_wfid[err.wfid] ||= as.call)[2] << err } schs.each { |sch| (by_wfid[sch['wfid']] ||= as.call)[3] << sch } # TODO: trackers wfids = by_wfid.keys.sort wfids = wfids.reverse if opts[:descending] # re-adjust list of wfids, only take what was found wfids.collect { |wfid| info = by_wfid[wfid] info ? self.new(context, *info) : nil }.compact end |
Instance Method Details
#all_tags ⇒ Object
Returns a hash tagname => array of feis of all the tags set in the process instance.
165 166 167 168 169 170 |
# File 'lib/ruote/dboard/process_status.rb', line 165 def all_variables.remap do |(fei, vars), h| vars.each { |k, v| (h[k] ||= []) << v if FlowExpressionId.is_a_fei?(v) } end end |
#all_variables ⇒ Object
Returns a hash fei => variable_hash containing all the variable bindings (expression by expression) of the process instance.
139 140 141 142 143 144 145 146 |
# File 'lib/ruote/dboard/process_status.rb', line 139 def all_variables return nil if @expressions.empty? @expressions.each_with_object({}) do |exp, h| h[exp.fei] = exp.variables if exp.variables end end |
#current_tree ⇒ Object
Returns the current version of the process definition tree. If no manipulation (gardening) was performed on the tree, this method yields the same result as the #original_tree method.
Returns nil if there are no expressions (happens in the case of an orphan workitem)
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 |
# File 'lib/ruote/dboard/process_status.rb', line 497 def current_tree return nil if @expressions.empty? h = Ruote.decompose_tree(original_tree) @expressions.sort { |e0, e1| e0.fei.expid <=> e1.fei.expid }.each { |e| trigger = e.tree[1]['_triggered'] tree = if trigger && trigger != 'on_re_apply' t = original_tree_from_parent(e).dup t[1]['_triggered'] = trigger t else e.tree end h.merge!(Ruote.decompose_tree(tree, e.fei.expid)) } Ruote.recompose_tree(h) end |
#definition_name ⇒ Object
For a process
Ruote.process_definition :name => 'review', :revision => '0.1' do
reviewer
end
will yield ‘review’.
217 218 219 220 221 222 |
# File 'lib/ruote/dboard/process_status.rb', line 217 def definition_name @root_expression && ( @root_expression.attribute('name') || @root_expression.attribute_text) end |
#definition_revision ⇒ Object
For a process
Ruote.process_definition :name => 'review', :revision => '0.1' do
reviewer
end
will yield ‘0.1’.
233 234 235 236 237 238 |
# File 'lib/ruote/dboard/process_status.rb', line 233 def definition_revision @root_expression && ( @root_expression.attribute('revision') || @root_expression.attribute('rev')) end |
#hinspect(indent, h) ⇒ Object
367 368 369 370 371 372 373 374 375 376 |
# File 'lib/ruote/dboard/process_status.rb', line 367 def hinspect(indent, h) if h h.collect { |k, v| s << "#{' ' * indent}#{k.inspect}: #{v.inspect}" }.join("\n") else "#{' ' * indent}(nil)" end end |
#inspect ⇒ Object
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 |
# File 'lib/ruote/dboard/process_status.rb', line 378 def inspect vars = variables rescue nil avars = (all_variables || {}).remap { |(k, v), h| h[Ruote.sid(k)] = v } s = [ "== #{self.class} ==" ] s << '' s << " wfid: #{wfid}" s << " name: #{definition_name}" s << " revision: #{definition_revision}" s << " last_active: #{last_active}" s << " launched_time: #{launched_time}" s << '' s << " expressions: #{@expressions.size}" s << '' @expressions.each do |e| s << " #{e.fei.to_storage_id}" s << " | #{e.name}" s << " | _rev: #{e.h._rev.inspect}" s << " | * #{e.state} *" if e.state s << " | #{e.attributes.inspect}" e.children.each do |ce| s << " | . child-> #{Ruote.sid(ce)}" end if e.children.any? s << " | timers: #{e.h.timers.collect { |t| t[1] }}" if e.h.timers s << " | (flanking)" if e.h.flanking s << " `-parent--> #{e.h.parent_id ? e.parent_id.to_storage_id : 'nil'}" end s << '' s << " schedules: #{@schedules.size}" if @schedules.size > 0 @schedules.each do |sched| s << " * #{sched['original']}" s << " #{sched['flavour']} #{sched['at']}" s << " #{sched['action']}" s << " #{Ruote.sid(sched['target']) rescue '** no target **'}" end s << '' end s << " stored workitems: #{@stored_workitems.size}" s << '' s << " initial workitem fields:" if @root_expression s << hinspect(4, @root_expression.h.applied_workitem['fields']) else s << " (no root expression identified)" end s << '' s << " variables:"; s << hinspect(4, vars) s << '' s << " all_variables:"; s << hinspect(4, avars) s << '' s << " errors: #{@errors.size}" @errors.each do |e| s << " ***" s << " #{e.fei.to_storage_id} :" if e.fei s << " action: #{e.action}" s << " message: #{e.}" s << " trace:" e.trace.split("\n").each do |line| s << " #{line}" end s << " details:" (e.details || '').split("\n").each do |line| s << " #{line}" end if e.respond_to?(:deviations) s << " deviations:" (e.deviations || []).each do |line| s << " #{line.inspect}" end end s << " fields:"; s << hinspect(6, e.fields) end # TODO: add trackers s.join("\n") + "\n" end |
#last_active ⇒ Object
Returns a parseable UTC datetime string which indicates when the process was last active.
335 336 337 338 |
# File 'lib/ruote/dboard/process_status.rb', line 335 def last_active @expressions.collect { |fexp| fexp.h.put_at }.max end |
#launched_time ⇒ Object
Returns a Time instance indicating when the process instance was launched.
350 351 352 353 |
# File 'lib/ruote/dboard/process_status.rb', line 350 def launched_time @root_expression && @root_expression.created_time end |
#leaves ⇒ Object
Returns the expressions where the flow is currently, ak the leaves of the execution tree.
Whereas #position only looks at participant expressions (and errors), #leaves looks at any expressions that is a leave (which has no child at this point).
Returns an array of FlowExpression instances. (Note that they may have their attribute #error set).
287 288 289 290 291 292 |
# File 'lib/ruote/dboard/process_status.rb', line 287 def leaves expressions.inject([]) { |a, exp| a.select { |e| ! exp.ancestor?(e.fei) } + [ exp ] } end |
#original_tree ⇒ Object
Returns the process definition tree as it was when this process instance was launched.
343 344 345 346 |
# File 'lib/ruote/dboard/process_status.rb', line 343 def original_tree @root_expression && @root_expression.original_tree end |
#past_tags ⇒ Object
Returns the list of “past tags”, tags that have been entered and left.
The list elements look like:
[ full_tagname, fei_as_string, nil_or_left_status, variables ]
For example:
[ 'a', '0_1_0!8f233fb935c!20120106-jagitepi', nil, {} ]
or
[ 'stage0/stage1', '0_1_0!8fb935c666d!20120106-jagitepi', 'cancelling', nil ]
The second to last entry is nil when the tag (its expression) replied normally, if it was cancelled or something else, the entry contains a string describing the reason (‘cancelling’ here). The last entry is the variables as they were at the tag point when the execution left the tag.
192 193 194 195 196 197 |
# File 'lib/ruote/dboard/process_status.rb', line 192 def (@root_expression ? @root_expression.variables['__past_tags__'] : nil ) || [] end |
#position ⇒ Object
Returns the ‘position’ of the process.
pdef = Ruote.process_definition do
alpha :task => 'clean car'
end
wfid = engine.launch(pdef)
sleep 0.500
engine.process(wfid) # => [["0_0", "alpha", {"task"=>"clean car"}]]
A process with concurrent branches will yield multiple ‘positions’.
It uses #workitems underneath.
If you want to list all the expressions where the “flow currently is” regardless they are participant expressions or errors, look at the #leaves method.
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 |
# File 'lib/ruote/dboard/process_status.rb', line 259 def position workitems.collect { |wi| r = [ wi.fei.sid, wi.participant_name ] params = (wi.fields['params'] || {}).dup params.delete('ref') if err = errors.find { |e| e.fei == wi.fei } params['error'] = err. end r << params r } end |
#root_expression_for(fei) ⇒ Object
Given an expression id, returns the root (top ancestor) for its expression.
115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/ruote/dboard/process_status.rb', line 115 def root_expression_for(fei) sfei = Ruote.sid(fei) exp = @expressions.find { |fe| sfei == Ruote.sid(fe.fei) } return nil unless exp return exp if exp.parent_id.nil? root_expression_for(exp.parent_id) end |
#root_expressions ⇒ Object
Returns a list of all the expressions that have no parent expression. The list is sorted with the deeper (closer to the original root) first.
101 102 103 104 105 106 107 108 109 110 |
# File 'lib/ruote/dboard/process_status.rb', line 101 def root_expressions roots = @expressions.select { |e| e.h.parent_id == nil } roots = roots.each_with_object({}) { |e, h| h["#{e.h.fei['expid']}__#{e.h.fei['subid']}"] = e } roots.keys.sort.collect { |k| roots[k] } end |
#root_workitem ⇒ Object
Returns the workitem as was applied at the root expression.
Returns nil if no root expression could be found.
298 299 300 301 302 303 |
# File 'lib/ruote/dboard/process_status.rb', line 298 def root_workitem return nil unless root_expression Ruote::Workitem.new(root_expression.h.applied_workitem) end |
#tags ⇒ Object
Returns a hash tagname => fei of tags set at the root of the process instance.
Returns nil if there is no defined root expression.
153 154 155 156 157 158 159 160 |
# File 'lib/ruote/dboard/process_status.rb', line 153 def if variables Hash[variables.select { |k, v| FlowExpressionId.is_a_fei?(v) }] else nil end end |
#to_dot(opts = {}) ⇒ Object
Returns a ‘dot’ representation of the process. A graph describing the tree of flow expressions that compose the process.
463 464 465 466 467 468 469 470 471 |
# File 'lib/ruote/dboard/process_status.rb', line 463 def to_dot(opts={}) s = [ "digraph \"process wfid #{wfid}\" {" ] @expressions.each { |e| s.push(*e.send(:to_dot, opts)) } @errors.each { |e| s.push(*e.send(:to_dot, opts)) } s << '}' s.join("\n") end |
#to_h ⇒ Object
Outputs the process status as a hash (easily JSONifiable).
475 476 477 478 479 480 481 482 483 484 485 486 487 488 |
# File 'lib/ruote/dboard/process_status.rb', line 475 def to_h %w[ expressions errors stored_workitems schedules trackers ].each_with_object({}) do |a, h| k = a == 'stored_workitems' ? 'workitems' : a v = self.send(a) v = v.collect { |e| e.respond_to?(:h) ? e.h : e } h[k] = v end end |
#to_s ⇒ Object
355 356 357 358 359 360 361 362 363 364 365 |
# File 'lib/ruote/dboard/process_status.rb', line 355 def to_s '(' + [ "process_status wfid '#{wfid}'", "expressions #{@expressions.size}", "stored_workitems #{@stored_workitems.size}", "errors #{@errors.size}", "schedules #{@schedules.size}", "trackers #{@trackers.size}" ].join(', ') + ')' end |
#variables ⇒ Object
Returns the process variables set for this process instance.
Returns nil if there is no defined root expression.
131 132 133 134 |
# File 'lib/ruote/dboard/process_status.rb', line 131 def variables @root_expression && @root_expression.variables end |
#wfid ⇒ Object
Returns the unique identifier for this process instance.
201 202 203 204 205 206 |
# File 'lib/ruote/dboard/process_status.rb', line 201 def wfid l = [ @expressions, @errors, @stored_workitems ].find { |l| l.any? } l ? l.first.fei.wfid : nil end |
#workitems ⇒ Object
Returns a list of the workitems currently ‘out’ to participants
For example, with an instance of
Ruote.process_definition do
concurrence do
alpha :task => 'clean car'
bravo :task => 'sell car'
end
end
calling engine.process(wfid).workitems will yield two workitems (alpha and bravo).
Warning : do not confuse the workitems here with the workitems held in a storage participant or equivalent.
322 323 324 325 326 327 328 329 330 |
# File 'lib/ruote/dboard/process_status.rb', line 322 def workitems @expressions.select { |fexp| #fexp.is_a?(Ruote::Exp::ParticipantExpression) fexp.h.name == 'participant' }.collect { |fexp| Ruote::Workitem.new(fexp.h.applied_workitem) } end |