Hello,
maybe you could have a look at Participant#on_reply. It was recently enhanced to work with "instantiated participants" (participants instantiated at registration time (I have the impression that it's what you use)).
The test case is :
http://github.com/jmettraux/ruote/blob/ruote2.1/test/functional/ft_43_participant_on_reply.rb
Basically, it's a callback triggered when the workitem reaches back the participant.
I'm not sure I fully understand your case. It seems that if there are multiple workitems in your engine, any of them will wake up the waiting thread when reaching a storage participant.
Or, some speculation : what about a participant that explicitely wakes up your thread ?
---8<---
pdef = Ruote.process_definition do
sequence do
participant 'patient'
do_the_work
participant 'waker'
end
end
module Bedroom
@guests = {}
def self.sleep (label)
@guests[label] = Thread.current
Thread.current.stop
end
def self.wakeup (label)
t = @guests.delete(label)
t.wakeup
end
end
class PatientParticipant < Ruote::StorageParticipant
def reply (workitem)
label = workitem.fei.to_s
workitem.fields['sleeper'] = label
super(workitem)
Bedroom.sleep(label)
end
end
class WakerParticipant
include Ruote::LocalParticipant
def consume (workitem)
Bedroom.wakeup(workitem.fields.delete('sleeper'))
reply_to_engine(workitem)
end
end
--->8---
(This assumes that the worker is running in the same ruby process as the web application).
When the patient participant replies to the engine, the replying thread is put to sleep. It's woken up a bit later by a specific 'waker' participant.
You could also rely on something inside "do_the_work" to wake up the thread.
Sorry if I'm completely off.
Best regards,
--
John Mettraux - http://jmettraux.wordpress.com
Hello Ian,
you want the thread to wakeup only when it's been put to sleep at bravo and it then reaches charlie ?
What is the rule for threads put to sleep at alpha and delta ?
Hello,
you could do something like
def idle?
7.times do
Thread.pass
return false if @context.storage.get_msgs.size > 0
end
true
end
But I'm afraid it's a bit brittle (there could be schedules kicking in
a bit later).
> --------------------------------------------------------------------------------------------- <
> # This is unavoidable given Ruote's design of never knowing what's
> going to
> # happen next.
> --------------------------------------------------------------------------------------------- <
Framing that one :-)
"embrace the asynchronous"
Ouch, I have trouble re-formatting that each time. It looks painful.
> I then call this on my engine: `add_service 'patient_notifier',
> 'notifiers', 'Workflow::PatientNotifier'`
>
> The rest of the code is pretty similar to the code I posted before
> with some slight refactoring to remove it from Participants and put it
> into a singleton Patient module (sans #consume method, of course).
>
> I'm interested to hear your thoughts on this approach.
I read at some point that you'd like to know your position in the flow
in order to not sleep. Maybe this could help :
( gist at http://gist.github.com/483796 )
---8<---
require 'rubygems'
require 'ruote'
engine = Ruote::Engine.new(Ruote::Worker.new(Ruote::HashStorage.new))
pdef = Ruote.define do
concurrence do
alpha
sequence do
bravo
charlie
end
delta
end
end
class MyParticipant
include Ruote::LocalParticipant
def consume (workitem)
p [
workitem.participant_name,
:parent_type, parent_type(workitem),
:last?, last?(workitem)
]
reply(workitem)
end
# Returns the name of the parent expression (like 'sequence' or
# 'concurrence').
#
def parent_type (workitem)
fetch_flow_expression(workitem).parent.name
end
# Returns true if the participant expression with this workitem is the
# last in the list of children of the parent expression
# (warning, it doesn't mean that much when in a concurrence expression).
#
def last? (workitem)
fexp = fetch_flow_expression(workitem)
fexp.fei.child_id == fexp.parent.tree[2].length - 1
end
end
engine.register_participant '.+', MyParticipant
wfid = engine.launch(pdef)
engine.wait_for(wfid)
--->8---
I hope it helps.
Thanks for sharing !
It looks good.