Ok, I finally got something working, but I'm afraid it will be
brittle. I figured that using a service and notification events would
be more flexible, produce code with looser coupling with Ruote, and
provide a path toward better asynchronicity in the future. So, I
removed the wait code from my participants and added it to a static
module. I then created a service called "PatientNotifier" like this:
# Wakes a thread that is stopped using `Patient::wait_for`. It will
wake the
# thread in the following
circumstances:
#
# * when a "dispatch" event is received that has a workitem that
matches the
# criteria passed to
`Patient::wait_for`
# * when a "reply" event is received, and no further events are
received for
# up to a `listen_for`
seconds.
#
# This latter circumstance is potentially problematic if some
messages take
# more than `listen_for` seconds to be processed, but it's the only
way to
# detect situations where a "dispatch" won't be sent until something
else
# happens, eg. when one branch of one or more concurrent branches
has ended.
# This is unavoidable given Ruote's design of never knowing what's
going to
# happen next.
class PatientNotifier <
ApplicationNotifier
class << self
def subscribe_to; %w(reply dispatch);
end
def listen_for; 1;
end
end
def initialize *args
super *args
@lock =
Mutex.new
end
def dispatches; @lock.synchroni...@dispatches}; end
def dispatches= new_d; @lock.synchroni...@dispatches = new_d};
end
def listen_thread; @lock.synchroni...@listen_thread}; end
def listen_thread= new_d; @lock.synchroni...@listen_thread =
new_d}; end
def notify msg
send "handle_#{msg["action"]}",
msg
end
def handle_reply
msg
start_listening
msg
end
def handle_dispatch msg
self.dispatches << msg if dispatches
continue
msg
end
def continue
msg
wi =
Ruote::Workitem.new(msg["workitem"])
::Patient.continue wi
end
def start_listening msg
if listen_thread
listen_thread.kill
end
self.listen_thread = Thread.new do
listen
msg
end
end
def listen msg
self.dispatches =
[]
sleep self.class.listen_for
if self.dispatches.empty?
continue msg
end
ensure
self.listen_thread, self.dispatches = nil, nil
end
end
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.
--
you received this message because you are subscribed to the "ruote users" group.
to post : send email to [email protected]
to unsubscribe : send email to [email protected]
more options : http://groups.google.com/group/openwferu-users?hl=en