scope of workflow variables

83 views
Skip to first unread message

Klaus Schmidtmamn

unread,
Apr 19, 2012, 6:10:23 PM4/19/12
to ruote
hello folks,

i experimented a little with ruote and found the following miss-
understanding:
When i ask for a budget value within one "cursor" into one
"concurrence", so i can't access to this variable within an other
curson in the same concurrence.

My Structure is the following:

sequence do
concurrence do

cursor do # c1
participant 'askForBudget'
echo 'budget: ${f:budget}'
participant 'sayMyBudget'
end

cursor do # c2
participant 'sayMyBudget'
rewind :unless => '3 < 1'
end

end

end
end


engine.register_participant :sayMyBudget do |workitem|
puts "globale Budget-Variable: #{workitem.fields['budget']}"
end


"sayMyBudget" only works into curso #c1. why?

John Mettraux

unread,
Apr 19, 2012, 6:57:29 PM4/19/12
to openwfe...@googlegroups.com

On Thu, Apr 19, 2012 at 03:10:23PM -0700, Klaus Schmidtmamn wrote:
>
> i experimented a little with ruote and found the following miss-
> understanding:
> When i ask for a budget value within one "cursor" into one
> "concurrence", so i can't access to this variable within an other
> curson in the same concurrence.
>
> sequence do
> concurrence do
> cursor do # c1
> participant 'askForBudget'
> echo 'budget: ${f:budget}'
> participant 'sayMyBudget'
> end
> cursor do # c2
> participant 'sayMyBudget'
> rewind :unless => '3 < 1'
> end
> end
> end
>
> engine.register_participant :sayMyBudget do |workitem|
> puts "globale Budget-Variable: #{workitem.fields['budget']}"
> end
>
> "sayMyBudget" only works into curso #c1. why?

Hello Klaus,

welcome to the ruote mailing list.

Process variables are not the same thing as workitem fields [1]

You cursor 1 and your cursor 2 work on a different copy of the original
workitem. When the concurrence ends, the workitems get merged [2].

There are various ways to do the thing you seem to be doing, the most obvious
one is:

---8<---
sequence do
participant 'askForBudget'
participant 'sayMyBudget'
end
--->8---

I.e. keep the "budget" as a workitem field and never call "sayMyBudget"
before "askForBudget".


Best regards,

--
John Mettraux - http://lambda.io/processi

[1] http://ruote.rubyforge.org/vars_and_fields.html
[2] http://ruote.rubyforge.org/exp/concurrence.html

Klaus Schmidtmamn

unread,
Apr 20, 2012, 3:37:13 PM4/20/12
to ruote
Hello John,

thank you for your answer, executing the participants into sequence
seems to be the best way.

An Other question: (Maybe a beginners question, but i have to start
through with ruote into the next weeks)...

The configuration:
If i have one ruby file, containing one Processdefinition

8<-----------------
pdef = Ruote.process_definition :name => 'test' do...
8<-----------------

and one launcher:

8<-----------------
...
wfid = engine.launch(pdef)
engine.wait_for(:informTimeout)
...
8<-----------------

As a single instance, everything works fine.

If i start this file in 2 different terminals, i get 2 different
wfid's:

the 1st terminal's output:
8<-----------------
fei : 0_0_0!0a07ade70aa2f61d64eb2369fa5b13d1!20120420-sazadage
wfid : 20120420-sazadage
expid : 0_0_2
subid : 006d2501d04df7dc1709be397bf611fe
engine_id : engine
...
8<-----------------

and the 2nd terminal's output:
8<-----------------
fei : 0_0_0!b9af9b46ec94e36019285685bc247737!20120420-powowope
wfid : 20120420-powowope
expid : 0_0_2
subid : 7f2e1c1f459b2e4bbb164c9fe3c4f3b5
engine_id : engine
...
8<-----------------

But the processdefinition drives crazy asyncronously: output from the
first instance comes in the 2nd terminal and so on.

My Questions:

1. What have i to do in order to execute multi process-instances at
the same time? My goal is later to built a web-application for multi-
authors in order to generate knowledge-Objects which are thebase fpr
new knowledge-modells (its part of my master thesis). Is it possible
to configure one processinstance with a web-session-id?

2. Is there a way to interact with instance variables between
different Process-Instances e.g. for looking some ressources ect. Or
whats it the mainly used technology in order to synchronize some
instances?

3. Is "ruote-fluo" still the state of the art in ruote-process-
visualization?

Thank you for answering some beginners-questions,
Greetings,
Klaus
> John Mettraux -http://lambda.io/processi

John Mettraux

unread,
Apr 20, 2012, 4:21:16 PM4/20/12
to openwfe...@googlegroups.com

Hello Klaus,

from what you describe, you seem to be using a file storage shared by your
two "engines", making them effectively a single "engine". The worker in
terminal 1 and the one in terminal 2, each launch a workflow and then compete
for pieces of work.

Not all storage implementations are "multi worker" enabled. The documentation
at http://ruote.rubyforge.org/configuration.html#storage should help.


> My Questions:
>
> 1. What have i to do in order to execute multi process-instances at
> the same time?

You just described how you ran two process instances thanks to two workers
above...


> My goal is later to built a web-application for multi-
> authors in order to generate knowledge-Objects which are thebase fpr
> new knowledge-modells (its part of my master thesis). Is it possible
> to configure one processinstance with a web-session-id?

I guess that you could launch a process instance and pass a workitem field
containing the web-session-id:

---8<---
@dashboard.launch(process_definition, 'web_session_id' => web_session_id)
--->8---

This sets the workitem field 'web_session_id' at launch. Of course, you can
set more fields.

I have the impression you're trying to build a web wizard (because you want
to store that "web-session-id"). What if the workflow is meant to live longer
than a browser session?

You could decide not to care about "web sessions" and simply have different
tasklists or worklists by users and they pick workitems there and proceed
them or cancel them (ruote-kit's web interface is a some example of that).


> 2. Is there a way to interact with instance variables between
> different Process-Instances e.g. for looking some ressources ect. Or
> whats it the mainly used technology in order to synchronize some
> instances?

It's not possible. Instead it's much easier for different workflow instances
to share resources by pointing at them.

---8<---
@dashboard.launch(
process_definition,
'customer_id' => customer_id,
'item_id' => item_id)
--->8---

Here the process instance carries customer_id and item_id around and updates
those in the database. It doesn't carry the whole objects in the workitem
fields.

Now you can extend that and use it to make process instances
"communicate"...

I'm probably not replying exactly to your question, but if you step back a
few paces and look at the whole house you'll think about different ways to
ask your question.


> 3. Is "ruote-fluo" still the state of the art in ruote-process-
> visualization?

It's more of an example. I'm working on a new, SVG, version, but I have
trouble finding time for it, https://github.com/jmettraux/ruote-fluo/tree/svg.


Hope it helps, kind regards,

Klaus Schmidtmamn

unread,
Apr 22, 2012, 4:00:01 PM4/22/12
to openwfe...@googlegroups.com
Hello John,

thank you for you for your answer.

Some questions are still open:

Yes, you are right, i need more a customer-based workflow-instance than a web-session. So i tried this:
 
wfid = dashboard.launch(pdef, 'customer_id' => customer_id) .. with an individual given ID. But the same: If i start 2 Session (each in a different terminal), the output of the one occurs in the other and the input of the other terminal occurs asynchronously in the other terminal window.
Maybe i need a separate process-definition-name?

I think, i understood the theory: one piece of work will be done by multi users. But in my case, each user (web-client) has to go through the same workflow (from the beginning until the end). The instances differentiate only by the different user-choice of sub-processes, they want to go through. Do You know a better way to synchronize the sessions for each client?

An other problem i saw is the Timeout of 60s. Even if i give a much longer timeout to my main sequence like

 sequence :timeout => '2000s' do...

there is a timeout after 60s:

/home/hugo/.rvm/gems/ruby-1.9.2-p318/gems/ruote-2.3.0/lib/ruote/log/wait_logger.rb:144:in `block in wait_for': waited for [:informTimeout], timed out after 60s (Ruote::LoggerTimeout)

i found it is the default value for timeout, defined here:

/ruby-1.9.2-p318/gems/ruote-2.3.0/lib/ruote/log/wait_logger.rb
@timeout = context['wait_logger_timeout'] || 60 # in seconds:

But how can i set the timeout to infinitely?

An Other question is, how to interrupt and reopen a started process-instance? Is such an interrupt also possible in a shell client?

With "ruote-fluo" i am nearly happy. Wasn't there a possibility to start and stop the instances? Or was this only possible with ruote-kit?

Last but not least:
why do i have to use this Dashboard now, instead of the engine?


Hope to get the overview once.

Greetings from Germany,
Klaus





--
you received this message because you are subscribed to the "ruote users" group.
to post : send email to openwfe...@googlegroups.com
to unsubscribe : send email to openwferu-use...@googlegroups.com
more options : http://groups.google.com/group/openwferu-users?hl=en

John Mettraux

unread,
Apr 22, 2012, 6:20:43 PM4/22/12
to openwfe...@googlegroups.com

On Sun, Apr 22, 2012 at 10:00:01PM +0200, Klaus Schmidtmamn wrote:
>
> Some questions are still open:
>
> Yes, you are right, i need more a customer-based workflow-instance than a
> web-session.

I never wrote you needed more of a customer-based workflow-instance than a
web-session [-based one]...

> So i tried this:
>
> wfid = dashboard.launch(pdef, 'customer_id' => customer_id) .. with an
> individual given ID. But the same: If i start 2 Session (each in a
> different terminal), the output of the one occurs in the other and the
> input of the other terminal occurs asynchronously in the other terminal
> window.

You took my answer to your question number 2 as an answer to your unnumbered
initial question... It's very difficult to have a conversation with such a
confusing technique of yours.

Please define what do you mean by "starting a Session". Don't hesitate to use
a gist: https://gist.github.com/

> Maybe i need a separate process-definition-name?

No. What we need is a common understanding.

> I think, i understood the theory: one piece of work will be done by multi
> users.

Let me rephrase. If you have multiple ruote workers, they will compete for
pieces of work, one piece of work will be executed by a single ruote worker.

If now by "piece of work" you mean "workitem" and by "user" you mean a human
using a web browser, then a workitem will be done by a human if he's
presented with the workitem in some way (in ruote-kit this is done via the
"workitems" tab).

> But in my case, each user (web-client) has to go through the same
> workflow (from the beginning until the end). The instances differentiate
> only by the different user-choice of sub-processes, they want to go
> through. Do You know a better way to synchronize the sessions for each
> client?

This is unclear. Could you please explain your use case as it looks for the
human using the system?

> An other problem i saw is the Timeout of 60s. Even if i give a much longer
> timeout to my main sequence like
>
> sequence :timeout => '2000s' do...

The problem here is that you're using "wait_for" which is a testing/demo
tool.

In production one lets the workflow instances run their course and never uses
wait_for.

wait_for is used in tests and demonstrations, to pause the main thread of
execution while the workflow is running, then, when wait_for returns the
control to the main thread, to verify if the workflow instance or the whole
system is in the desired state.

As said in my previous answer, you should investigate "worklists", ie points
where workitems accumulate and users (humans) may do/perform them. I'm sorry,
but in my previous answer, I forgot to mention that there is a ready made
"worklist" in the form of Ruote::StorageParticipant.

https://github.com/jmettraux/ruote/blob/f36a911378d8fbaebfd172a12b0e53477e182dc2/lib/ruote/part/storage_participant.rb

Your use of wait_for indicates you're misunderstanding ruote. I have the
impression you're trying to make it work synchronously instead of
understanding it and leveraging its asynchronoucity.

Once again, are you trying to build a "wizard system":
http://en.wikipedia.org/wiki/Wizard_%28software%29 ?

> there is a timeout after 60s:
>
> /home/hugo/.rvm/gems/ruby-1.9.2-p318/gems/ruote-2.3.0/lib/ruote/log/wait_logger.rb:144:in
> `block in wait_for': waited for [:informTimeout], timed out after 60s
> (Ruote::LoggerTimeout)
>
> i found it is the default value for timeout, defined here:
>
> /ruby-1.9.2-p318/gems/ruote-2.3.0/lib/ruote/log/wait_logger.rb
> @timeout = context['wait_logger_timeout'] || 60 # in seconds:
>
> But how can i set the timeout to infinitely?

You can set the timeout to infinity with a negative value:

https://github.com/jmettraux/ruote/blob/f36a911378d8fbaebfd172a12b0e53477e182dc2/lib/ruote/dashboard.rb#L553-560

> An Other question is, how to interrupt and reopen a started
> process-instance? Is such an interrupt also possible in a shell client?

Please define "interrupt".
Please define "reopen".

> With "ruote-fluo" i am nearly happy. Wasn't there a possibility to start
> and stop the instances? Or was this only possible with ruote-kit?

ruote-fluo != ruote-kit

Have you noticed that ruote-kit uses ruote-fluo? ruote-fluo is only meant to
render workflow definitions. The administration console is ruote-kit,
ruote-fluo is only a rendering tool (repeating that).
Someone might want to use ruote-fluo only and provide his own tool for
process administration instead of ruote-kit.

> Last but not least:
> why do i have to use this Dashboard now, instead of the engine?

Because I made a mistake when I first named it an "Engine". The enactment of
workflow instances is performed by workers, the sum of the workers is the
engine, there is no execution happening in Ruote::Engine / Ruote::Dashboard,
it's only a dashboard, there are a few indicators and a few wheels to turn,
but the real thing is happening in Ruote::Worker on top of storage
implementations.

I'm now trying to show a good example and use "Dashboard".

> Hope to get the overview once.

Let's do our best.


Best regards,

Klaus Schmidtmamn

unread,
Apr 23, 2012, 6:23:17 PM4/23/12
to openwfe...@googlegroups.com
Hello John,

>> What we need is a common understanding.
Thank you for being patient, in order to get a common understanding with me and my problem. Maybe i have a little wrong understanding of ruote, because i have also to do with JBPM-Workflow-Definitions. So now, I would like to describe my work more in detail to you:
Yes, my system will be a web wizard, used by human users. The only difference is, that many users do the same steps (a step is in my understanding one participant – in jbpm syntax called „node“ – right?). The sequence of the steps is defined in the workflow. Each user starts his own workflow (process-instance) because everyone has to go through the same steps.
The effort is, that each person works through the same nodes (participants), but can make different notes to each participant. In the future all notes of all participant from all users will be summarized.

>> Please define "interrupt"
Interrupting means for me, to persist the current position (what was the last finished participant of a user) in order to continue the process-instance at an other time.

>> Please define "reopen"
This is the „read the last persistent state“ from above. In order to go to the next unfinished participant.

Maybe you can give me a hint for an architecture of my problem.

greetings,
Klaus


John Mettraux

unread,
Apr 24, 2012, 9:34:36 AM4/24/12
to openwfe...@googlegroups.com

On Tue, Apr 24, 2012 at 12:23:17AM +0200, Klaus Schmidtmamn wrote:
>
> Maybe you can give me a hint for an architecture of my problem.

Not sure if it's an architecture or if it focuses on your problem, but I've
compiled an example at

https://github.com/jmettraux/for_klaus

It's composed of a server (ruote worker) and a client.

Log in as "alice" and launch a new flow, select a workitem, add a note to it,
proceed it, ... Exit the client, come back into it, check again the "notes",
...

I hope this will help you. If you have further questions, please ask.


Kind regards,

Klaus Schmidtmamn

unread,
Apr 26, 2012, 4:47:18 PM4/26/12
to ruote
Hello John,

Thank you for your well explaining example, I understood at least 95%
of it. It made fun to proceed the workitems, each user has. I think
it’s the right direction for achieving my goal.

My main fault was, that i did not realize that participants are the
real users or roles acting through the workflow. I thought thar
participants are synonyms for my well known JBPM-Nodes, but now, i
have the right view.

For now, I have 2 questions about it:

1. Why do I have to use the worker
(Ruote::Worker.new(Ruote::FSStorage…) within the server Script and why
does it work without the “worker” within the client script?

If I put this part into the client script, multiple clients are able
to work without the server(“server worker” ) :

@dboard = Ruote::Dashboard.new(
Ruote::Worker.new(
Ruote::FsStorage.new('ruote_work')))

2. What do you think, will be the next step in order to integrate this
client into a rails controller which writes out json-objects or plain
html-stream? I do not want you solving my complete work; I just need
an inspiration how to continue.

Thank you very much,
Greetings
Klaus

John Mettraux

unread,
Apr 26, 2012, 8:57:47 PM4/26/12
to openwfe...@googlegroups.com

Hello Klaus,

On Thu, Apr 26, 2012 at 01:47:18PM -0700, Klaus Schmidtmamn wrote:
>
> 1. Why do I have to use the worker
> (Ruote::Worker.new(Ruote::FSStorage…) within the server Script and why
> does it work without the “worker” within the client script?
>
> If I put this part into the client script, multiple clients are able
> to work without the server(“server worker” ) :
>
> @dboard = Ruote::Dashboard.new(
> Ruote::Worker.new(
> Ruote::FsStorage.new('ruote_work')))

Well spotted.

If you have a workflow that is waiting for a long time or has a "cron"
expression and only rely on workers inside of a client, you could have a
situation where, when no clients are running, the workflows are actually not
executing (there is no worker picking up tasks). Of course, whenever a client
starts, the execution resumes, but that is annoying when you
told to a workflow to "do that at this point in time" and it happens, only
later (too late?), when a client finally kicks in.

If you have ruote running side by side (in the same Ruby process) with a
webserver, it's OK, both need to be running all the time. But what I've seen
from production is that people want to seperate the webserver from any
worker. You want to serve more web requests and you are usually happy with a
pack of workers running in the backend.

For a small organization having the worker side by side with the webserver is
OK (and it's easy to test and debug).


> 2. What do you think, will be the next step in order to integrate this
> client into a rails controller which writes out json-objects or plain
> html-stream? I do not want you solving my complete work; I just need
> an inspiration how to continue.

Well, the commands in the "for_klaus" client encompass both the controller
and the view, it's then easy to

class WorkflowController
def launch
pdef = extract_pdef_from_params
fields = extract_initial_workitem_fields_from_params
@wfid = $dashboard.launch(pdef, fields)
end
end

ruote-kit (https://github.com/kennethkalmer/ruote-kit) is full example,
although rack-centered, not rails-centered, but it's easy to find inspiration
for controllers and views in there.

https://github.com/kennethkalmer/ruote-kit/blob/master/lib/ruote-kit/resources/processes.rb
https://github.com/kennethkalmer/ruote-kit/blob/master/lib/ruote-kit/views/process.html.haml
...


Best regards,

Klaus Schmidtmamn

unread,
May 3, 2012, 3:24:52 PM5/3/12
to ruote
Hello John,

since i tested a little around with the "for_klaus" example, i already
have some questions.

1.
Because i have many users with different skill level, i thought it
make sense to have participants with the role of "skill-level".
All Users (roles) should be active at the same time, so i think i need
a Definition like this:

Ruote.define do

concurrence do

subprocess :ref => 'skill_0_Handling'
subprocess :ref => 'skill_1_Handling'
subprocess :ref => 'skill_2_Handling'
subprocess :ref => 'skill_3_Handling'

end

define 'skill_0_Handling' do
cursor do
...
rewind
end
end


define 'skill_1_Handling' do
cursor do
...
rewind
end
end
...

You think my thoughts are correct here?

2.
In my "for_klaus" exmaple, there is always only a task defined e.g.

user_alice :task => 'tune engine'

But what if i will execute my own functionality instead of a task
"tune engine"? I thought this could work with the consumer in the
class like this:

class Skill0
include Ruote::LocalParticipant

def initialize(opts)
@opts = opts
end

def on_workitem
begin
puts 'say sth...'
reply
rescue
re_dispatch(:in => @opts['delay'] || '1s')
end
...

But here, i do not understand the registration mechanism:

You wrote into the registration part:

@dboard.register do
participant /^user_/, Ruote::StorageParticipant
end

I think this will register all users in the given Processdefinition.
But in order to script a well implementation for each participant, i
need sth like this:

@dboard.register_participant "user_skill0", Skill0

right?

Where can I find an example of interaction between Processdefinition
(Subprocess) and a the participant-implementation?


3.
Is the "on_workitem" function within the participant-implementation
the same as i use
"proceed" (@dboard.storage_participant.proceed(@workitem)
@workitem = nil) in the "for_klaus" example?


4.
what is the diff between a "task" and an "activity"?

Thank you and greetings,
Klaus
>  https://github.com/kennethkalmer/ruote-kit/blob/master/lib/ruote-kit/...
>  https://github.com/kennethkalmer/ruote-kit/blob/master/lib/ruote-kit/...

John Mettraux

unread,
May 3, 2012, 5:52:10 PM5/3/12
to openwfe...@googlegroups.com

Hello Klaus,
I cannot read your thoughts ;-)

This could be rewritten as something like:

---8<---
Ruote.define do

citerator :on => [ 0, 1, 2, 3 ], :to_f => 'level' do
handle :level => '$f:level'
end

define :handle do
cursor do
# level is passed as variable ${v:level}...
end
end
end
--->8---

But you could launch one process instance per skill level, it would be
cleaner and the you don't seem to need to have those parallel things linked
together.

---8<---
(0..3).each { |i| @dboard.launch(pdef, 'skill_level' => i) }
--->8---

I'm probably wrong, but my excuse is that I don't know your use case.
You could do something like:

---8<---
class SkilledParticipant
include Ruote::LocalParticipant

def on_workitem
level = workitem.participant_name.match(/^skill_(\d+)/)[1].to_i
# ...
end
end

@dboard.register do
participant /^skill_/, Klaus::SkilledParticipant
participant /^user_/, Ruote::StorageParticipant
end
--->8---

In this example you can have all the "skill_0123" go to SkilledParticipant
and have the skill level interpreted on the fly.

Of course, nothing prevents you from being a bit more static:

---8<---
@dboard.register do
(0..3).each do |i|
participant "skill_#{i}", Klaus::SkilledParticipant, 'level' => i
end
participant /^user_/, Ruote::StorageParticipant
end
--->8---

(where your skilled participant knows about its level via the 'level' option
it's passed each time it's instantiated).


> Where can I find an example of interaction between Processdefinition
> (Subprocess) and a the participant-implementation?

I'm not sure if it's the right answer, but I've got the feeling that my
SkilledParticipant example is an example of such an interaction because the
participant extract infos at runtime from the name under which it's invoked.


> 3.
> Is the "on_workitem" function within the participant-implementation
> the same as i use
> "proceed" (@dboard.storage_participant.proceed(@workitem)
> @workitem = nil) in the "for_klaus" example?

No, the #on_workitem method is a general participant method, while the
#proceed method is almost only found in Ruote::StorageParticipant.

#on_workitem is called by ruote right after it instantiated the participant
to make it perform work on the workitem.

#proceed is called by clients to ruote that are using the
Ruote::StorageParticipant, have just performed some work related to a
workitem and want that workitem to leave the storage participant and
proceed/resume into its workflow instance.


> 4.
> what is the diff between a "task" and an "activity"?

Well, a "task" is just a convention I use to place a participant invocation
into some context.

---8<---
Ruote.define do
klaus :task => 'ask question'
john :task => 'answer question'
end
--->8---

John and Klaus will receive workitems. The task is just a label on the
workitem. Maybe the participant implementations uses it, maybe not. From the
ruote [engine] point of view, it's just a piece of payload information.

There is no "activity" concept in ruote.

Sometimes it's convenient to label a workitem "task" or "activity" in
documentation or explanations, but for the engine, it's only about handling
workitems to participants.


Kind regards,

--
John Mettraux - http://lambda.io/jmettraux

Klaus Schmidtmamn

unread,
May 4, 2012, 12:16:16 PM5/4/12
to ruote
Hello John,

Thank you for answering. To reduce my confusion I have some more
questions:

1.
The construct:

@dboard.register do
participant /^skill_/, Klaus::SkilledParticipant
participant /^user_/, Ruote::StorageParticipant
end

means that all participants, containing a "skill" in her name are
instantiated as SkillParticipants and "user" as "StorageParticipant".
Do I need this "participant /^user_/, Ruote::StorageParticipant" if
there are only "skill-participants"? E.g. if each Workflow-Action
depends on the skill-level of the user, I only need "participant /
^skill_/, Klaus::SkilledParticipant"?
What does "Klaus" mean in "Klaus::SkilledParticipant"?
For me, it only works without the "Klaus::"- prefix.


2.
What actually confuses me most is the way how to realize individual
steps within my process-definition for the different users with
different skill level:
What I did is the following: After starting the client, the user can
input his name (not mandatory) and his skill-level (mandatory) like
this:

@dboard.register do
participant /^skill_/, SkilledParticipant
#participant /^user_/, Ruote::StorageParticipant
end

print 'username: '; @user = gets.strip
print 'skill-level: '; @skill = Integer(gets.strip)

2.
Does it make sense to launch the process-definition only with the
required skill-level... like this:

puts 'user= '+@user
puts 'skill= '+String(@skill)

wfid = @dboard.launch('./defs/def0.rb', 'skill_level' => @skill)

How to read this 'skill-level' parameter within the Process-
Definition? I think the skill-parameter has no influence over the
procss-definition if it starts like this:

citerator :on => [ 0, 1, 2, 3 ], :to_f => 'level' do
echo 'level= ${f:level}'
handle :level => '$f:level'
end
...

To me it seems like no matter what variable is given to the "launch",
the process-definition is deployed for all participants? I do not
understand what influence a variable like
'skill_level' => @skill has at this position.

3.
On the other hand side, you gave me the example below with the "skill-
level as variable". But how can I combine the registered participants
with this variable?
This confused me... So how would you change this part to make sense:

Ruote.define do

citerator :on => [ 0, 1, 2, 3 ], :to_f => 'level' do
echo 'level= ${f:level}'
handle :level => '$f:level'
end

define :handle do
cursor do
# level is passed as variable ${v:level}...

echo 'my skill level is: ${v:level}'

echo 'do level 0 jobs' , :if => '${v:level} == 0'
echo 'do level 1 jobs' , :if => '${v:level} == 1'

# this seems to be double conditioned...
# why using a variable like "${v:level}" if I have the different
skilled participants?

skill_0 :task => 'easy' , :if => '${v:level} == 0'
skill_1 :task => 'normal' , :if => '${v:level} == 1'
skill_2 :task => 'hard' , :if => '${v:level} == 2'
skill_3 :task => 'very hard', :if => '${v:level} == 3'

end


4.
Concerning to your explanation of task: "skill_0 :task => 'easy'" will
only say what to do, but in what way I can execute a function or a
method, if this workflow-position is reached?
I think on sth. like "skill_1 :task => doSth()'
Where should this function exist?

Greetings + Thank you for beeing patient

Klaus

John Mettraux

unread,
May 4, 2012, 6:36:23 PM5/4/12
to openwfe...@googlegroups.com

Hello Klaus,

On Fri, May 04, 2012 at 09:16:16AM -0700, Klaus Schmidtmamn wrote:
>
> 1.
> The construct:
>
> @dboard.register do
> participant /^skill_/, Klaus::SkilledParticipant
> participant /^user_/, Ruote::StorageParticipant
> end
>
> means that all participants, containing a "skill" in her name are
> instantiated as SkillParticipants and "user" as "StorageParticipant".
> Do I need this "participant /^user_/, Ruote::StorageParticipant" if
> there are only "skill-participants"?

No.

> E.g. if each Workflow-Action
> depends on the skill-level of the user, I only need "participant /
> ^skill_/, Klaus::SkilledParticipant"?

Yes.

> What does "Klaus" mean in "Klaus::SkilledParticipant"?
> For me, it only works without the "Klaus::"- prefix.

Sorry, it's a namespace:

---8<---
module Klaus
class SkilledParticipant
include Ruote::LocalParticipant
# ...
end
end
--->8---


> 2.
> What actually confuses me most is the way how to realize individual
> steps within my process-definition for the different users with
> different skill level:
> What I did is the following: After starting the client, the user can
> input his name (not mandatory) and his skill-level (mandatory) like
> this:
>
> @dboard.register do
> participant /^skill_/, SkilledParticipant
> #participant /^user_/, Ruote::StorageParticipant
> end
>
> print 'username: '; @user = gets.strip
> print 'skill-level: '; @skill = Integer(gets.strip)
>
> Does it make sense to launch the process-definition only with the
> required skill-level... like this:
>
> puts 'user= '+@user
> puts 'skill= '+String(@skill)
>
> wfid = @dboard.launch('./defs/def0.rb', 'skill_level' => @skill)

Yes, I think so.

> How to read this 'skill-level' parameter within the Process-
> Definition?

when you do

wfid = @dboard.launch('./defs/def0.rb', 'skill_level' => @skill)

you're starting a workflow instance with a workitem field "skill_level" set
to @skill.

---8<---
$engine.register :klaus, Ruote::StorageParticipant

pdef = Ruote.define do
klaus, :task => 'go to ${f:city}'
end

$engine.launch(pdef, 'city' => 'Oslo')
$engine.launch(pdef, 'city' => 'Bratislava')
$engine.launch(pdef, 'city' => 'Vilnius')
--->8---

> I think the skill-parameter has no influence over the
> procss-definition if it starts like this:
>
> citerator :on => [ 0, 1, 2, 3 ], :to_f => 'level' do
> echo 'level= ${f:level}'
> handle :level => '$f:level'
> end
> ...

Indeed.

> To me it seems like no matter what variable is given to the "launch",
> the process-definition is deployed for all participants? I do not
> understand what influence a variable like
> 'skill_level' => @skill has at this position.

It's not a variable, it's a workitem field.

Please re-read my previous email carefully, you'll notice that I proposed you
two distinct solutions. If now you mix them, of course it will be confusing.

> 3.
> On the other hand side, you gave me the example below with the "skill-
> level as variable". But how can I combine the registered participants
> with this variable?
> This confused me... So how would you change this part to make sense:
>
> (...)
>
> skill_3 :task => 'very hard', :if => '${v:level} == 3'

You can do:

participant :ref => 'skill_${f:skill_level}', :task => 'x'


> 4.
> Concerning to your explanation of task: "skill_0 :task => 'easy'" will
> only say what to do, but in what way I can execute a function or a
> method, if this workflow-position is reached?
> I think on sth. like "skill_1 :task => doSth()'
> Where should this function exist?

You can't do that.

You could do:

---8<---
class SkilledParticipant
include Ruote::LocalParticipant

def on_workitem
task = workitem.params['task']
case task
when do_this
Something.do_this
when do_that
Something.do_that
else
raise "unknown task: #{task.inspect}"
end
reply
end
end
--->8---

So many ways to skin a cat.

Klaus Schmidtmamn

unread,
May 8, 2012, 11:14:28 AM5/8/12
to ruote
Hello John,
Is there a way to combine the advantages of the storage-participant
(central storage, show all open workitems, proceeding single steps and
so on) with the individual implementation of a participant like
“Klaus::SkilledParticipant” e.g. heredity?

Is there a way to choose open workitems or select workitems within my
own implementation or a participant?

Thank You
Klaus

John Mettraux

unread,
May 8, 2012, 4:30:48 PM5/8/12
to openwfe...@googlegroups.com

Hello Klaus,

On Tue, May 08, 2012 at 08:14:28AM -0700, Klaus Schmidtmamn wrote:
>
> Is there a way to combine the advantages of the storage-participant
> (central storage, show all open workitems, proceeding single steps and
> so on) with the individual implementation of a participant like
> “Klaus::SkilledParticipant” e.g. heredity?
>
> Is there a way to choose open workitems or select workitems within my
> own implementation or a participant?

Yes, "inheritance",

---8<---
module Klaus

class SkilledParticipant < Ruote::LocalParticipant

def on_workitem

workitem.fields['hello'] = world

super
end
end
end

# ...

$dashboard.register do
participant /^skill_/, Klaus::SkilledParticipant
# ...
end
--->8---

A way of grabbing those workitems afterwards:

---8<---
skilled_workitems = $dashboard.storage_participant.select { |wi|
wi.participant_name.match(/^skill_/)
}
--->8---

Please start a new discussion thread if you have a new question, Also save
bytes by not copying mindlessly the dead part of the discussion at the bottom
of your emails.

Cheers,

Klaus Schmidtmamn

unread,
May 9, 2012, 4:44:22 AM5/9/12
to ruote
Hello John.

Thank you for answering and sorry for using this thread one last
time:
Just some yes-now questions:

when You told me to use inheritance, You wrote:

1.
-----------------------------------------------------------------------------------------
---8<---
module Klaus

class SkilledParticipant < Ruote::LocalParticipant

def on_workitem
---8<---

but i think you mean:

class SkilledParticipant < Ruote::StorageParticipant

include Ruote::LocalParticipant

right?



2.
-----------------------------------------------------------------------------------------


all Participants, existing in a processdefinition have to be
registered before launching the process-definition

Else, i get one:

2 54:36.388 20 er * 20120509-0654-nayumori-bitsuroke ae5bb
0_0_0_6
20120509-0654-nayumori-bitsuroke RuntimeError
20120509-0654-nayumori-bitsuroke unknown participant or subprocess
'user_4'

right?

3.
------------------------------------------------------------------------------------------

Within my

class SkilledParticipant < Ruote::LocalParticipant

do I need a "reply_to_engine(workitem)" behind the "super-call"?

-----------------------------------------------------------------------------------------

For some more questions, I started a new thread.

Thank you.

Klaus

John Mettraux

unread,
May 9, 2012, 4:49:24 AM5/9/12
to openwfe...@googlegroups.com

Hello Klaus,

On Wed, May 09, 2012 at 01:44:22AM -0700, Klaus Schmidtmamn wrote:
>
> when You told me to use inheritance, You wrote:
>
> 1.
>
> ---8<---
> module Klaus
>
> class SkilledParticipant < Ruote::LocalParticipant
>
> def on_workitem
> ---8<---
>
> but i think you mean:
>
> class SkilledParticipant < Ruote::StorageParticipant
>
> include Ruote::LocalParticipant
>
> right?

No, because Ruote::StorageParticipant alreadys includes
Ruote::LocalParticipant.

> all Participants, existing in a processdefinition have to be
> registered before launching the process-definition
>
> Else, i get one:
>
> 2 54:36.388 20 er * 20120509-0654-nayumori-bitsuroke ae5bb
> 0_0_0_6
> 20120509-0654-nayumori-bitsuroke RuntimeError
> 20120509-0654-nayumori-bitsuroke unknown participant or subprocess
> 'user_4'
>
> right?

Right.

> Within my
>
> class SkilledParticipant < Ruote::LocalParticipant
>
> do I need a "reply_to_engine(workitem)" behind the "super-call"?

No, because reply_to_engine(workitem) makes the workflow go on, (cf your new
question).


Best regards,
Reply all
Reply to author
Forward
0 new messages