Hello Ruote world!
I've recently inherited a project from a former colleague which makes heavy
use of Ruote. We're experiencing some issues on Heroku which I'm trying to
make sense of -- I've gathered some data, but haven't been able to figure
it out myself since I'm still learning Ruote, so I'm hoping someone here
can help :)
Take the following snippets of code which support our Ruote implementation:
================
#config/initializers/ruote.rb
if Rails.env=="production"
uri = URI.parse(ENV["REDISTOGO_URL"])
REDIS = Redis.new(:host => uri.host, :port => uri.port, :password =>
uri.password, thread_safe: true)
RUOTE_STORAGE = Ruote::Redis::RedisStorage.new(REDIS, {})
else
storage_path="ruote_storage_#{Rails.env}"
RUOTE_STORAGE = Ruote::FsStorage.new(storage_path)
end
RUOTE = if defined?(Rake)
Ruote::Dashboard.new(RUOTE_STORAGE)
else
Ruote::Dashboard.new(Ruote::Worker.new(RUOTE_STORAGE))
end
================
#models/approval.rb
after_commit :create_ruote_process, on: :create
.
.
.
def create_ruote_process
RUOTE.register_participant('approval_step', ApprovalParticipant)
RUOTE.register_participant('disburse_step', DisburseParticipant)
RUOTE.register_participant('prior_approver', PriorApprover)
RUOTE.register_participant('approval_terminate', TerminateParticipant)
RUOTE.register_participant :set_esc do |item|
item.fields["esc"] = true
end
RUOTE.register_participant :unset_esc do|item|
item.fields["esc"] = false
end
RUOTE.launch(definition_obj, work_item_params, {})
end
================
#definition_obj.inspect
"[\"define\", {\"name\"=>\"approval_process\", \"revision\"=>\"0.1\"},
[[\"cursor\", {}, [[\"sequence\", {\"on_error\"=>\"approval_terminate\"},
[[\"concurrence\", {\"count\"=>1}, [[\"approval_step\",
{\"approver_id\"=>\"2\", \"approval_step_id\"=>\"1\"}, []],
[\"approval_step\", {\"approver_id\"=>\"3\", \"approval_step_id\"=>\"1\"},
[]], [\"approval_step\", {\"approver_id\"=>\"1\",
\"approval_step_id\"=>\"1\"}, []], [\"approval_step\",
{\"approver_id\"=>\"4\", \"approval_step_id\"=>\"1\"}, []],
[\"approval_step\", {\"approver_id\"=>\"5\", \"approval_step_id\"=>\"1\"},
[]], [\"approval_step\", {\"approver_id\"=>\"6\",
\"approval_step_id\"=>\"1\"}, []], [\"approval_step\",
{\"approver_id\"=>\"7\", \"approval_step_id\"=>\"1\"}, []]]],
[\"disburse_step\", {}, []]]]]]]]"
#work_item_params.inspect
{:approval_id=>71}
================
If we were to run this locally, noisy output gives us something resembling
this:
6 59:34.094 80: pa * regex: approval_step, action: participant_registered
7 59:34.097 80: pa * regex: disburse_step, action: participant_registered
8 59:34.098 80: pa * regex: prior_approver, action: participant_registered
9 59:34.100 80: pa * regex: approval_terminate, action:
participant_registered
0 59:34.101 80: pa * regex: set_esc, action: participant_registered
1 59:34.102 80: pa * regex: unset_esc, action: participant_registered
true
2 59:34.114 80: la * 20130124-1659-kegatoyu-dabotodi stash: nil, wi:
[0!48914...!, 1], t: [define, {name: approval_process, revision: 0.1},
[[cursor, {}, [[sequence, {on_error: approval_terminate}, [[concurrence,
{count: 1}, [[approval_step, {approver_id: 2, approval_step_id: 1}, []],
[approval_step, {approver_id: 3, approval_step_id: 1}, []], [approval_step,
{approver_id: 1, approval_step_id: 1}, []], [approval_step, {approver_id:
4, approval_step_id: 1}, []], [approval_step, {approver_id: 5,
approval_step_id: 1}, []], [approval_step, {approver_id: 6,
approval_step_id: 1}, []], [approval_step, {approver_id: 7,
approval_step_id: 1}, []]]], [disburse_step, {}, []]]]]]]]
0 define name: approval_process, revision: 0.1
0_0 cursor
0_0_0 sequence on_error: approval_terminate
0_0_0_0 concurrence count: 1
0_0_0_0_0 approval_step approval_step_id: 1, approver_id: 2
0_0_0_0_1 approval_step approval_step_id: 1, approver_id: 3
0_0_0_0_2 approval_step approval_step_id: 1, approver_id: 1
0_0_0_0_3 approval_step approval_step_id: 1, approver_id: 4
0_0_0_0_4 approval_step approval_step_id: 1, approver_id: 5
0_0_0_0_5 approval_step approval_step_id: 1, approver_id: 6
0_0_0_0_6 approval_step approval_step_id: 1, approver_id: 7
0_0_0_1 disburse_step
3 59:34.129 80: ap * 20130124-1659-kegatoyu-dabotodi b4d84 0_0_0 wi:
[0_0_0!b4d84...!, 1], t: [sequence, {on_error: approval_terminate},
[[concurrence, {count: 1}, [[approval_step, {approver_id: 2,
approval_step_id: 1}, []], [approval_step, {approver_id: 3,
approval_step_id: 1}, []], [approval_step, {approver_id: 1,
approval_step_id: 1}, []], [approval_step, {approver_id: 4,
approval_step_id: 1}, []], [approval_step, {approver_id: 5,
approval_step_id: 1}, []], [approval_step, {approver_id: 6,
approval_step_id: 1}, []], [approval_step, {approver_id: 7,
approval_step_id: 1}, []]]], [disburse_step, {}, []]]], pi: 0_0!3dcc7...!
4 59:34.141 80: ap * 20130124-1659-kegatoyu-dabotodi e177a 0_0_0_0
wi: [0_0_0_0!e177a...!, 1], t: [concurrence, {count: 1}, [[approval_step,
{approver_id: 2, approval_step_id: 1}, []], [approval_step, {approver_id:
3, approval_step_id: 1}, []], [approval_step, {approver_id: 1,
approval_step_id: 1}, []], [approval_step, {approver_id: 4,
approval_step_id: 1}, []], [approval_step, {approver_id: 5,
approval_step_id: 1}, []], [approval_step, {approver_id: 6,
approval_step_id: 1}, []], [approval_step, {approver_id: 7,
approval_step_id: 1}, []]]], pi: 0_0_0!b4d84...!
5 59:34.154 80: ap * 20130124-1659-kegatoyu-dabotodi ab3f8
0_0_0_0_1 wi: [0_0_0_0_1!ab3f8...!, 2], t: [participant, {approver_id: 3,
approval_step_id: 1, ref: approval_step}, []], pi: 0_0_0_0!e177a...!
6 59:34.162 80: ap * 20130124-1659-kegatoyu-dabotodi 4b549
0_0_0_0_3 wi: [0_0_0_0_3!4b549...!, 2], t: [participant, {approver_id: 4,
approval_step_id: 1, ref: approval_step}, []], pi: 0_0_0_0!e177a...!
7 59:34.173 80: ap * 20130124-1659-kegatoyu-dabotodi 474be
0_0_0_0_5 wi: [0_0_0_0_5!474be...!, 2], t: [participant, {approver_id: 6,
approval_step_id: 1, ref: approval_step}, []], pi: 0_0_0_0!e177a...!
(this may not be all of the noisy output... sometimes it gets eaten in the
console)
================
Everything runs very smoothly locally -- we normally use file-based storage
for Ruote locally, but it runs fine with Redis as well.
On Heroku, things start misbehaving. Behaviors I'm observing are:
- Workflow items are generated and put in Redis
- ApprovalParticipant on_workitems do not appear to fire. In these test
cases, we would expect these to be fired first.
- In noisy output on Heroku, we occasionally see a message pop such as
below:
- 1 36:36.206 00: fa * 20130124-1636-korezome-pachisosa 85839
0_0_0 immediate: false, wi: [0_0_0_0_0!91fe9...!, 3]
- I've also occasionally seen output like below with an exception:
- er * 20130123-2145-bipidibi-mupodita 30776 0_0_0
20130123-2145-bipidibi-mupodita * class: RuntimeError
20130123-2145-bipidibi-mupodita * msg: persist failed for
0_0_0!30776c0a5e83924f9dc3
- The behavior is very inconsistent. When launching, sometimes it works
for all participants, sometimes it works for a few participants, but
normally it works for none.
- When outputting the process() for a wfid which we expected to be
worked, we see output generally like below:
===================
RUOTE.process("20130124-1634-darakuyu-hifudobo")
=> == Ruote::ProcessStatus ==
wfid: 20130124-1634-darakuyu-hifudobo
name: approval_process
revision: 0.1
last_active: 2013-01-24 16:34:02.750968 UTC
launched_time: 2013-01-24 16:34:01.997249 UTC
expressions: 5
0!600f525fe922499a9358160e0eefeb62!20130124-1634-darakuyu-hifudobo
| define
| _rev: "2"
| {"name"=>"approval_process", "revision"=>"0.1"}
| . child->
0_0!a8c3b2d14677a4ac8fa46f07ba22f038!20130124-1634-daraku
`-parent--> nil
0_0!a8c3b2d14677a4ac8fa46f07ba22f038!20130124-1634-darakuyu-hifudobo
| cursor
| _rev: "2"
| {}
| . child->
0_0_0!dfdaf6dee7282f14566515b29d0e4291!20130124-1634-dara
bo
`-parent-->
0!600f525fe922499a9358160e0eefeb62!20130124-1634-darakuyu
0_0_0!dfdaf6dee7282f14566515b29d0e4291!20130124-1634-darakuyu-hifudobo
| sequence
| _rev: "4"
| * failing *
| {"on_error"=>"approval_terminate"}
| . child->
0_0_0_0!dd1cbed3f68ddb3055b4bb6f3447e1ed!20130124-1634-da
dobo
`-parent-->
0_0!a8c3b2d14677a4ac8fa46f07ba22f038!20130124-1634-daraku
0_0_0_0!dd1cbed3f68ddb3055b4bb6f3447e1ed!20130124-1634-darakuyu-hifudob
| concurrence
| _rev: "6"
| * cancelling *
| {"count"=>1}
| . child->
0_0_0_0_3!655ded9a22c753c5c5b97b4b61cf89e6!20130124-1634-
fudobo
`-parent-->
0_0_0!dfdaf6dee7282f14566515b29d0e4291!20130124-1634-dara
bo
0_0_0_0_3!655ded9a22c753c5c5b97b4b61cf89e6!20130124-1634-darakuyu-hifud
| participant
| _rev: "3"
| * cancelling *
| {"approver_id"=>"4", "approval_step_id"=>"1",
"ref"=>"approval_step
`-parent-->
0_0_0_0!dd1cbed3f68ddb3055b4bb6f3447e1ed!20130124-1634-da
dobo
schedules: 0
stored workitems: 0
initial workitem fields:
"approval_id": 21
variables:
"approval_process": ["0", ["define", {"name"=>"approval_process",
"revis
}, [["cursor", {}, [["sequence", {"on_error"=>"approval_terminate"},
[["conc
"count"=>1}, [["approval_step", {"approver_id"=>"1",
"approval_step_id"=>"1"
pproval_step", {"approver_id"=>"2", "approval_step_id"=>"1"}, []],
["approva
approver_id"=>"3", "approval_step_id"=>"1"}, []], ["approval_step",
{"approv
, "approval_step_id"=>"1"}, []]]], ["disburse_step", {}, []]]]]]]]]
all_variables:
"0!a656a8009786640c8a20c8be12ca3182!20130124-1636-korezome-pachisosa":
{
rocess"=>["0", ["define", {"name"=>"approval_process", "revision"=>"0.1"},
[
{}, [["sequence", {"on_error"=>"approval_terminate"}, [["concurrence",
{"cou
"approval_step", {"approver_id"=>"1", "approval_step_id"=>"1"}, []],
["appro
{"approver_id"=>"2", "approval_step_id"=>"1"}, []], ["approval_step",
{"appr
3", "approval_step_id"=>"1"}, []], ["approval_step", {"approver_id"=>"4",
"a
p_id"=>"1"}, []]]], ["disburse_step", {}, []]]]]]]]]}
errors: 0
===================
If I'm interpreting it right, the workflow fails after approval_process is
reached. However, the workflow also doesn't list any errors.
I know the information doesn't really jive together that well, and it may
be that there are multiple causes in the mix. I have a few questions which
will hopefully narrow this down:
- Are there any inherent issues with implementing Ruote on Heroku? Are
there any "gotchas" that we need to consider?
- If there are exceptions to be caught, which is the best way to catch
them? I've tried using on_error in my process definition, but I can't tell
if it's actually being tripped (I can't log or trace anything from within
the block)
- Is there any way to observe the worker process to see if it is
experiencing issues?
- Could moving the launcher within a rake task alleviate this sort of
behavior?
I know that's a lot to go through, and would be grateful to anyone who can
take the time for it. Thanks in advance! :)
- EJI
--
--
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