| 2011-03-24 07:36:08 utc | jmettraux | tosch_le: hello, how are you doing ? |
| 2011-03-24 07:37:25 utc | tosch_le | fine, thanks. overloaded with work, though. how are you? |
| 2011-03-24 07:38:56 utc | jmettraux | doing fine, not too overloaded, some of the work I couldn't take with me |
| 2011-03-24 07:39:21 utc | jmettraux | I just pushed a ruote-kit change (the new StorageParticipant#proceed) feel free to merge when you have time |
| 2011-03-24 07:56:15 utc | tosch_le | specs are green, pushed. thanks! |
| 2011-03-24 07:56:25 utc | jmettraux | :-) |
| 2011-03-24 10:18:23 utc | gregormelhorn | Hello everybody! I got a question to ruote, hope somebody is willing to help :) I am trying to integrate ruote into a CRM system / callcenter. I now have a queue of all the customers waiting for their case to be processed, and whenever a callcenter agent clicks on a "get next customer" button, I want him to get the next "open" customer, that would be the best match for him based on certain criteria (method of payment, product type and so on). From wh |
| 2011-03-24 10:18:24 utc | gregormelhorn | I have seen, ruote is more for "push" workflow systems, how do I handle such a "pull" workflow? |
| 2011-03-24 10:20:17 utc | tosch_le | i'd use the StorageParticipant for that |
| 2011-03-24 10:20:59 utc | tosch_le | your queue is a kind of worklist which is handled by the storage participant |
| 2011-03-24 10:22:26 utc | gregormelhorn | ok, so the storage participant is a kind of "assign customer" participant that would know which customer to pick for a certain agent. |
| 2011-03-24 10:22:42 utc | gregormelhorn | how do I make that work on request of the callcenter agent? |
| 2011-03-24 10:24:20 utc | jmettraux | there is no push or pull in ruote |
| 2011-03-24 10:24:36 utc | tosch_le | no, the storageparticipant is dumb: it just has a list of open cases which should get done by an agent |
| 2011-03-24 10:25:09 utc | tosch_le | you can query the storage participant in a model of yours and let that decide which task you be assigned to which agent |
| 2011-03-24 10:25:38 utc | gregormelhorn | hmm, obviously I have problems of getting into the mindset of ruote :( |
| 2011-03-24 10:26:06 utc | tosch_le | or you could work with case groups and have a decision participant which decides to which group a case belongs |
| 2011-03-24 10:26:23 utc | tosch_le | sorry, there are quite a few possibilites |
| 2011-03-24 10:26:29 utc | jmettraux | gregormelhorn: it's not that, it's rather you're forgetting you're free to code stuff up |
| 2011-03-24 10:28:19 utc | jmettraux | cooking something, stay tuned |
| 2011-03-24 10:28:26 utc | gregormelhorn | ok, I thought of using ruote because there are other cases of flow logic where I think it would be a very good fit. but I still have no Idea how to connect the workflow to the "calculate now whenever the agent presses a button which customer it will get". Except to handle this completely outside of ruote of course. |
| 2011-03-24 10:29:03 utc | jmettraux | there is no "press a button" concept in ruote, it's not a front end lib like rails |
| 2011-03-24 10:29:16 utc | gregormelhorn | but I still have a feeling it somehow is business process logic, and so somehow should be some participant in ruote. maybe I am wrong with that assumption |
| 2011-03-24 10:29:35 utc | gregormelhorn | I know there is no press a button. I just don't know where to put that stuff in the process in a ruote way |
| 2011-03-24 10:32:50 utc | jmettraux | could this help https://github.com/tosch/ruote-kit/blob/master/lib/ruote-kit/resources/workitems.rb (it shows ruote-kit "controller" for workitems) |
| 2011-03-24 10:32:56 utc | tosch_le | one way: |
| 2011-03-24 10:33:03 utc | tosch_le | Ruote.process_definition do |
| 2011-03-24 10:33:11 utc | tosch_le | sequence do |
| 2011-03-24 10:33:18 utc | tosch_le | assign_agent # a participant implementation by yours which returns immediately |
| 2011-03-24 10:33:32 utc | tosch_le | process :agent => '${agent}' # a storage participant |
| 2011-03-24 10:33:37 utc | tosch_le | end |
| 2011-03-24 10:33:38 utc | tosch_le | end |
| 2011-03-24 10:34:12 utc | tosch_le | that way, you'd had the assignment in the process definition |
| 2011-03-24 10:35:01 utc | jmettraux | and here is another way, a reservation system added to StorageParticipant : https://gist.github.com/884853 |
| 2011-03-24 10:35:06 utc | tosch_le | but i suppose it's not the best solution: maybe you can be sure the agent is online in the assign_agent step, but you can't be sure he's still online in the process step |
| 2011-03-24 10:36:52 utc | gregormelhorn | I'll have a look at these now, thank you |
| 2011-03-24 10:39:39 utc | gregormelhorn | oh, I think I got it. |
| 2011-03-24 10:40:11 utc | gregormelhorn | ok, so I would launch a new workflow whenever an agents says it wants a new customer? then I would immediately calculate which one he gets and proceed from there? |
| 2011-03-24 10:40:40 utc | jmettraux | ? |
| 2011-03-24 10:40:56 utc | jmettraux | calculate which one of what ? |
| 2011-03-24 10:42:53 utc | tosch_le | in my opinion it's best to ensure that 'case' = 'workflow process' |
| 2011-03-24 10:43:10 utc | tosch_le | so, you launch a flow when a case is opened |
| 2011-03-24 10:43:40 utc | gregormelhorn | tosch_le: that's what I mean |
| 2011-03-24 10:43:52 utc | tosch_le | but it's not what you said ;-) |
| 2011-03-24 10:44:49 utc | gregormelhorn | ok, you're right. It also wasn't what I meant. |
| 2011-03-24 10:45:07 utc | gregormelhorn | so you mean I launch a workflow process whenver the case enters the system, right? |
| 2011-03-24 10:45:33 utc | tosch_le | do you use rails? |
| 2011-03-24 10:45:36 utc | gregormelhorn | yes |
| 2011-03-24 10:45:46 utc | tosch_le | yes, that's what i mean |
| 2011-03-24 10:46:01 utc | tosch_le | the process/case can sleep if there's no work to be done |
| 2011-03-24 10:46:41 utc | tosch_le | remember: ruote helps you to handle the whole life of the case, not only the step when an agent has to talk to a customer |
| 2011-03-24 10:46:57 utc | gregormelhorn | I hoped so. :) |
| 2011-03-24 10:49:28 utc | tosch_le | ok, so i'll try to be more explicit with proposing a solution: 1) the agent asks for a case to work on. 2) an model of yours queries the storage participant for the open cases. 3) it picks an appropriate case and marks it as being worked on by the agent, that way ensuring that it can't be picked by another agent. 4) the agent does his work. 5) when he's done, your controller calls the proceed action on the storage participant. |
| 2011-03-24 10:50:09 utc | tosch_le | john's gist does a part of that |
| 2011-03-24 10:51:53 utc | tosch_le | point 3) could be done by another participant like i showed above, but that could be problematic when the agent leaves just when point 4 is reached. |
| 2011-03-24 10:59:49 utc | jmettraux | an algo or a rule engine for picking the right workitem/task in the queue |
| 2011-03-24 11:01:15 utc | tosch_le | not all business logic should be in the process definition. it's ok to have the algo or rule engine in a model. |
| 2011-03-24 11:02:03 utc | jmettraux | +1 |
| 2011-03-24 11:02:08 utc | tosch_le | it's a bit like "fat model – lean controller" |
| 2011-03-24 11:02:17 utc | tosch_le | ruote is the controller in this case |
| 2011-03-24 11:03:21 utc | tosch_le | hey, i like that anlogy |
| 2011-03-24 11:03:44 utc | tosch_le | s/anlogy/analogy |
| 2011-03-24 11:06:10 utc | jmettraux | route to the queue, let the queue sort out the question "who should do the work" |
| 2011-03-24 11:06:20 utc | jmettraux | makes the queue reusable among workflows |
| 2011-03-24 11:06:46 utc | tosch_le | +1 |
| 2011-03-24 11:09:02 utc | jmettraux | gregormelhorn: do you know Paolo Negri ? |
| 2011-03-24 11:14:24 utc | jmettraux | tosch_le: relevant to ruote-kit http://www.infoq.com/presentations/BPM-with-REST |
| 2011-03-24 11:15:58 utc | tosch_le | thanks for the pointer |
| 2011-03-24 11:19:32 utc | gregormelhorn | back from lunch |
| 2011-03-24 11:19:40 utc | gregormelhorn | jmettraux: yes, I know him |
| 2011-03-24 11:19:41 utc | gregormelhorn | :) |
| 2011-03-24 11:19:53 utc | jmettraux | please say hi :-) |
| 2011-03-24 11:20:14 utc | gregormelhorn | hi? |
| 2011-03-24 11:20:34 utc | jmettraux | sorry, please say hello to him on beside of jmettraux |
| 2011-03-24 11:21:09 utc | gregormelhorn | ah, you are pairing? :) |
| 2011-03-24 11:21:12 utc | gregormelhorn | hi paolo! |
| 2011-03-24 11:25:24 utc | gregormelhorn | tosch_le: sounds good, the explicit solution |
| 2011-03-24 11:26:44 utc | gregormelhorn | though I don't like fat model, lean controller. :) I prefer "everybody does what he does best". |
| 2011-03-24 11:27:04 utc | jmettraux | nicely said |
| 2011-03-24 11:27:08 utc | tosch_le | so play around a bit with ruote, have a look at the docs and at the various examples flying around |
| 2011-03-24 11:27:42 utc | tosch_le | yes, but when saying "everything does what it does best", it results in fat models and lean controllers most times ;-) |
| 2011-03-24 11:27:56 utc | tosch_le | s/saying/applying/ |
| 2011-03-24 11:28:06 utc | gregormelhorn | hmm, I observed models getting too fat and controllers getting stubs. |
| 2011-03-24 11:28:19 utc | gregormelhorn | thus creating inter model dependencies via callbacks |
| 2011-03-24 11:28:22 utc | gregormelhorn | this sucks :) |
| 2011-03-24 11:28:46 utc | gregormelhorn | for testing and refactoring. we learned the hard way at our company :) |
| 2011-03-24 11:31:03 utc | gregormelhorn | I remember there is a blog entry or comment from DHH refering to that "fat models, lean controllers" stuff. basically what I remembered from it was something like 'let every part in MVC do what it does best - and don't move controller code into the model or the other way round' |
| 2011-03-24 11:31:27 utc | tosch_le | i would not contradict to that. |
| 2011-03-24 11:32:26 utc | tosch_le | we have common controller actions in the application controller here and overwrite them only when necessary. so much possibilities in ruby and rails |
| 2011-03-24 11:33:37 utc | gregormelhorn | so at our company nobody will callbacks that will access other models. this helped a lot. |
| 2011-03-24 11:33:46 utc | gregormelhorn | ok, enough philisophical stuff now :) |
| 2011-03-24 16:22:20 utc | dlazar | hello |
| 2011-03-24 16:22:29 utc | jmettraux | dlazar: hello and welcome to #ruote |
| 2011-03-24 16:22:58 utc | dlazar | I have a question about using rufus-scheduler |
| 2011-03-24 16:23:11 utc | jmettraux | ok |
| 2011-03-24 16:23:34 utc | dlazar | I would love to generate a schedule that I can examine, but not actually execute. |
| 2011-03-24 16:23:49 utc | dlazar | eg: every monday, starting next monday... do something... |
| 2011-03-24 16:23:59 utc | dlazar | but I just want to see what those mondays are... |
| 2011-03-24 16:24:20 utc | dlazar | so I was hoping there might be a way to tease that out of the schedular.. |
| 2011-03-24 16:24:47 utc | jmettraux | Rufus::Cronline.new('* * * * *').next_time(Time.now) |
| 2011-03-24 16:24:52 utc | dlazar | looking at the jobs... but I am not sure if there are actually any "Jobs" ... per se... |
| 2011-03-24 16:25:05 utc | jmettraux | where you replace '* * * * *' with your cron string |
| 2011-03-24 16:25:38 utc | jmettraux | sorry |
| 2011-03-24 16:25:49 utc | jmettraux | Rufus::CronLine.new('* * * * *').next_time(Time.now) |
| 2011-03-24 16:27:04 utc | dlazar | Rufus::ChronLine is part of schedular? |
| 2011-03-24 16:27:29 utc | jmettraux | Rufus::CronLine is |
| 2011-03-24 16:27:56 utc | dlazar | nice, thx |
| 2011-03-24 16:31:25 utc | dlazar | hmm.. looking at the code.. next_time gives me a date sure.. but I am looking to somehow generate a schedule of say, X events.. any thoughts on using the code to try that? |
| 2011-03-24 16:31:47 utc | dlazar | example... show me all the Mondays this month, and then all the Mondays in April... but that is it... |
| 2011-03-24 16:32:12 utc | dlazar | Chronic should help with that.. but it does not iterate over the concept of ALL |
| 2011-03-24 16:32:21 utc | dlazar | so I thought the scheduler might help for that |
| 2011-03-24 16:36:00 utc | jmettraux | dlazar: you can call it multiple times |
| 2011-03-24 16:36:10 utc | jmettraux | with a different "start time" |
| 2011-03-24 16:36:19 utc | jmettraux | I used "Time.now" for the example |
| 2011-03-24 16:36:38 utc | dlazar | yes.. I am thinking I can just use Chronic that way too... just call it X times and increment the base day... |
| 2011-03-24 16:36:45 utc | dlazar | Thx |
| 2011-03-24 16:36:59 utc | jmettraux | you're welcome |
| 2011-03-24 16:37:22 utc | jmettraux | IIRC there's a gem that deals with such time series, but I can't remember the name |
| 2011-03-24 16:38:12 utc | dlazar | I will try rubygems for that... I did not find a time series.. I have experience with Chronic and Whenever.. but not much else Time processing code... |
| 2011-03-24 16:40:41 utc | jmettraux | https://github.com/EdvardM/recurrence seems a bit asleep |
| 2011-03-24 16:41:02 utc | jmettraux | https://github.com/fnando/recurrence looks better |
| 2011-03-24 16:46:43 utc | dlazar | excellent! thx for the hot tip |
| 2011-03-24 16:52:55 utc | dlazar | w00t! That recurrence gem is exactly what the Dr. ordered... thanks again!!! |
| 2011-03-24 16:58:17 utc | jmettraux | you're welcome :-) |