On Thu, Jun 19, 2008 at 2:50 AM, Pauli <pauli...@gmail.com> wrote:
>
> I'd like to integrate webservices into a workflow - essentially
> mirroring this process:
>
> http://developer.amazonwebservices.com/connect/entry.jspa?externalID=635
>
> Would you use Ruote for this -- or is this actually better implemented
> as an 'acts_as_state_machine' type application? If you would use
> Ruote, can I do this with the project in it's current state?
I personally would use Ruote. Now for you it depends on your use case
/ context. Use whatever feels right for you.
act_as_a_state_machine is great for attaching a state to an active
record based object.
I have not used act_as_a_state_machine myself, but I'd like to
investigate it for tracking state of some resources and doing the
general orchestration with Ruote (state of entities vs state of
processes).
Ruote is all about letting you have "process instances" on their own.
Now nothing prevents you from creating a custom ProcessInstance class
(active record based) and tracking it with act_as_a_state_machine.
Some usual questions to ask to yourself :
- am I tracking the state of multiple objects ? Orchestrating ?
- change : would I rather change a process definition (new version) or
modify a set of states/transitions ?
- change : what happens if I have to migrate processes, can I cancel
the current processes, can I push object in the state I want ?
- ...
Back to your process, at first glance it looks like :
---8<---
class ScanProcess < OpenWFE::ProcessDefinition
sequence do
# implicit scan document
upload_document
select_keywords
review_keywords
_if :test => "${f:approved} == true" do
attach_keywords
end
end
end
--->8---
I didn't specify if the activities were participants or subprocesses,
it's rather drafty. "select_keywords" and "review_keywords" seems like
human activities, while upload_document and attach_keywords feel like
computer activities.
> Are there any current samples that illustrate launching a process on
> receipt of some event -- polling or blocking to wait on an event,
> rather than scheduled?
In order to launch a process, you have to feed a LaunchItem instance
to the engine.
---8<---
li = OpenWFE::LaunchItem.new(path_or_uri_to_process_definition)
li.attributes['subject'] = "0123.com request"
engine.launch(li)
--->8---
So your code / application can do the listening / waiting / blocking,
and launch a process in its embedded Ruote when needed.
There is another technique : attaching a listener to the engine :
http://github.com/jmettraux/ruote/tree/master/lib/openwfe/engine/engine.rb#L313-324
Some polling capabilites are included for this technique. It's
generally not much used. Often, the engine is embedded and fed
launchitems and workitems by the host application.
You might also want to take a look at the engine (and a bit of a
worklist) packaged as a web resource :
http://jmettraux.wordpress.com/2008/05/07/restful-workflow-engine-on-sinatra/
http://github.com/jmettraux/ruote-rest/tree/master
> What about webservice calls as process tasks?
In case of a soap webservice, you could have a look at
http://github.com/jmettraux/ruote/tree/master/lib/openwfe/participants/soapparticipants.rb
http://openwferu.rubyforge.org/participants.html#SoapParticipant
or at
http://github.com/jmettraux/ruote/tree/master/lib/openwfe/expressions/fe_http.rb
http://jmettraux.wordpress.com/2008/05/27/restful-bpm/
There is a list of out-of-the-box participants at :
http://openwferu.rubyforge.org/participants.html
> One thing I've kind of missed in the documentation so far is how to
> integrate the process workflow with external models and their
> persistant data -- I kind of want to see something in the process
> definition that isn't a person updating a form, but rather a call to
> some arbitrary code that takes the process state and related
> properties as inputs and returns a process status and ( potentially
> modified ) related properties as output.
This is usually done via something like :
---8<---
engine.register_participant "arbitrary_code" do |workitem|
puts "oh, I received this task, and it's about
#{workitem.attributes['subject']}"
workitem.attributes["approved_by_arbitrary_code"] = true
end
# or
engine.register_participant "arbitrary_code_2", MyArbitraryClass
--->8---
The idea is that you can provide participant implementations, and bind
instances of them in the engine under a participant name (which is
referenced by the process definitions). The process instances in an
engine share the same participants.
Hope this helps, best regards,
--
John Mettraux - http://jmettraux.wordpress.com
Hi Pauli,
I'll try to do my best at commenting your "framework". But I still
think that my answer is not that bad
(http://groups.google.com/group/openwferu-users/msg/74cbe707220a2d5b)
I'd recommend you start with tiny process definitions and then iterate
to a satisfying/full version.
> I take it that for each machine process in the sequence I would have
> to preceed this definition by something like:
Not really precede : participants are shared by process definitions
(different process definitions across different versions/revisions).
> ---8<---
> engine.register_participant "formatHit" do |workitem|
> (...)
> --->8---
> In particular, I'm confused about how to 'try again' in case of
> rejection or timeout -- see below.
Ruote has expressions for timeout :
http://openwferu.rubyforge.org/expressions.html#exp_timeout
And a retry could be build out of a loop (or cursor) :
http://openwferu.rubyforge.org/expressions.html#exp_cursor
> class AwsMtHit < OpenWFE::ProcessDefinition
> sequence do
> set :f => "needReviewing", :value => "false"
> set :f => "expired", :value => "false"
Those initial "set" could be done when preparing the LaunchItem instance.
> # launch => submits a hit to process
> # actually want to poll a queue of some sort, but
> # probably should start with an interactive form as
> # the simplest case??
>
> employee
Yes, start with something simple.
> # is this actually part of the process, or the launch?
> # I imagine that a template associated with the
> # launch item controls the actual format
>
> formatHit
If as much possible information can be fit and formatted correctly
when preparing the LaunchItem, it makes for shorter process
definitions.
> # is this actually part of the process, or the launch?
> # this would call the REST API with the formatted data
>
> submitHit
You've lost me, what REST API ?
> # is this actually part of the process, or the launch?
> # this somehow has to loop, checking for submissions
> # that need reviewing ( REST API call )
>
> waitForSubmission
>
> set :f => "approved", :value => "false"
> set :f => "rejected", :value => "false"
>
> # do I need an if test? Shouldn't be here unless
> # waitForSubmission exited -- if it exits without
> # a submission in need of Review, would it rather throw
> # an exception, and never reach this bit?
Simple ifs are not that bad.
> :if => "${f:needReviewing}" do
_if :test => "${f:needsReviewing}" do
> employee
>
>
> :if => "${f:rejected}" do
>
> # Let the submitter know ( REST API call )
>
> rejectSubmission
>
> # Try again ( REST API call )
>
> addAssignment
>
> # how to represent looping back to waitForSubmission??
> end
>
> :if => "${f:approved}" do
>
> # Let the submitter know ( REST API call )
>
> approveSubmission
>
> # this part would also depend on a definition included in
> # the template associated with the launch item
>
> processSubmission
>
> end
>
> end
>
>
> :if => "${f:expired}" do
>
> # Try again ( REST API call )
>
> addTime
>
> # how to represent looping back to waitForSubmission??
> end
>
>
> end
>
> end
It's hard for me to help you with that. I can help you understand
Ruote bit by bit (mouthful), but I can't do your job. Please have pity
on me and let's work self-contained question by self-contained
question.
Best regards,