If I were building what you were building, I would probably:
* Make several discrete CFCs that map to your message actions. * Use a factory object of some kind to bottleneck the process through a single entry point * Deal with worktoken validation/invalidation at the entry point to the factory functionYou can set up ColdSpring defined queues (or even database defined queues) of these CFCs in a series. That way, once the process starts, the control goes to the CFCs and everyone goes through a common entry point.
You can do your locks in this factory CFC or throw reasonable errors (possibly to other routes in the application, like the event: "HeyJerkYouSubmittedYourCartTwice_DoYouReallyWantUsToBillYouTwice" in the case of invalidation
DW
Brian G <mailto:[email protected]> Wednesday, February 20, 2013 11:33 AM On Tuesday, February 19, 2013 5:15:18 AM UTC-8, Chris Blackwell wrote:It's not so much there is complex logic in the controller, just that the steps are broken out to facilitate reuse of the methods. Here's what I mean:<broadcasts> <message name="needToProcessClass/> <message name="needToValidateClass/> <message name="needToSaveClass/> </broadcasts> And in the controllers:<cffunction name="doProcessClass" returntype="void" output="false" access="public"><cfargument name="event" type="any" /><cfset var objClass = arguments.event.makeEventBean(arguments.event.getValue("objClass")) /> <cfset objClass.setClubId(arguments.event.getValue("objCurrentClub").getId()) /><cfset arguments.event.setValue("objClass", objClass) /> </cffunction><cffunction name="doValidateClass" returntype="void" output="false" access="public"><cfargument name="event" type="any" /> <cfset var objClass = arguments.event.getValue("objClass") /> <cfset var error = objClass.validate() /> <cfif arrayLen(error)> <cfset arguments.event.getValue("msg").setFromCollection(error) /> <cfset arguments.event.addResult("invalidClass")> </cfif> </cffunction><cffunction name="doSaveClass" returntype="void" output="false" access="public"><cfargument name="event" type="any" /> <cfset var objClass = arguments.event.getValue("objClass") /> <cfset getClubService().saveClass(objClass) /><cfset arguments.event.getValue("msg").reportSaveSuccess('Class saved successfully!') /></cffunction>I do this because in the admin we may not validate but we want to reuse the same process and save code so this lets me reconstruct things. In the example I'm working with here, I want to basically lock from the process to the save step which is what Dan and I were discussing.Dan - to your point, certain times I would probably want both. Either deny the second request or just queue it. In most cases it's idempotent so a second request won't cause a problem so long as it runs after the first.Brian -- -- Model-Glue Sites: Home Page: http://www.model-glue.com Documentation: http://docs.model-glue.com Bug Tracker: http://bugs.model-glue.com Blog: http://www.model-glue.com/blog You received this message because you are subscribed to the Google Groups "model-glue" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/model-glue?hl=en ---You received this message because you are subscribed to the Google Groups "model-glue" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].For more options, visit https://groups.google.com/groups/opt_out. Chris Blackwell <mailto:[email protected]> Tuesday, February 19, 2013 8:15 AM Hi Brian,It shouldn't really be the case that your controller methods ends up being massive, if it is, then I'd hazard a guess that you're doing too much in your controller when really that code should be moved into a service layer.Things like business rules, queries, orm functions or transactions in a controller method are a red flag, and code needs re-factoringIf I have complicated processes to handle then I place them in a service, the service will then take whatever inputs are needed and process them. If an error occurs I have my service throw a custom exception that can be caught in the controller.function myControllerMethod(event) { var args = event.copyToScope({}, "foo,bar,baz"); try { var result = getMyService().doSomething(argumentCollection=args); } catch(InvalidFoo fooexc) { // foo was invalid, maybe redirect back to a form or something } catch(any e) { // something unexpected happened } // we're done, no errors, cool beans! }My controller has no idea what goes on inside the doSomething() method, only that it requires certain arguments, can throw a number of errors and returns a result. What the service does internally (maybe aggregating a dozen other service methods) is of no concern of the controller.As a rules of thumb, I only allow controllers to talk to services, and services to talk to gateways.Hope that helps, Chris -- -- Model-Glue Sites: Home Page: http://www.model-glue.com Documentation: http://docs.model-glue.com Bug Tracker: http://bugs.model-glue.com Blog: http://www.model-glue.com/blog You received this message because you are subscribed to the Google Groups "model-glue" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/model-glue?hl=en ---You received this message because you are subscribed to the Google Groups "model-glue" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].For more options, visit https://groups.google.com/groups/opt_out. Brian G <mailto:[email protected]> Monday, February 18, 2013 5:29 PMDan - thanks for the suggestion, will look into this. Would you use a queue to keep them separate or how, at the controller event level do you prevent it from running two work tokens simultaneously?On Tuesday, February 12, 2013 12:44:49 PM UTC-8, Dan Wilson - [email protected] wrote: ---- Model-Glue Sites: Home Page: http://www.model-glue.com Documentation: http://docs.model-glue.com Bug Tracker: http://bugs.model-glue.com Blog: http://www.model-glue.com/blog You received this message because you are subscribed to the Google Groups "model-glue" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/model-glue?hl=en ---You received this message because you are subscribed to the Google Groups "model-glue" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].For more options, visit https://groups.google.com/groups/opt_out. Dan Wilson <mailto:[email protected]> Tuesday, February 12, 2013 3:44 PMWould it be possible to use a Work-Token as your unit of work? Then you would be able to operate on the Work-Token, rather than the information from the session/user.The Work-Token can be a UUID or whatever you like. Generate this when the top-line entry point in the MG application is called. Process all your units of work against the Work-Token (even if you have to translate that into the user information for the database) and that way, even if the submission happens twice, the long running requests will be shielded from crossing streams.DW Brian G <mailto:[email protected]> Tuesday, February 12, 2013 3:22 PMI have some fairly lengthy processes that run one after another when saving e-commerce transactions to the system. For maintainability, these are spread across a few different events (which lets me error out and abort in certain cases cleanly). However, I do want to protect against a double-click or multiple submission from causing wonkiness (imagine the end of the routine empties out an array as things are processed successfully which leads to another running thread to wind up with an inconsistent array length).Normally I'd wrap it in a cflock but this spans multiple MG events. Any suggestions on another way to attack this? I don't really want to have one monster controller event as I like the readability and the ability to reuse individual broadcasts in other events.I suppose I could do some kind of a session flag and use that as a lock but that would really just stop the extra requests rather than queue them. Any other ideas?Brian -- -- Model-Glue Sites: Home Page: http://www.model-glue.com Documentation: http://docs.model-glue.com Bug Tracker: http://bugs.model-glue.com Blog: http://www.model-glue.com/blog You received this message because you are subscribed to the Google Groups "model-glue" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/model-glue?hl=en ---You received this message because you are subscribed to the Google Groups "model-glue" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].For more options, visit https://groups.google.com/groups/opt_out.
-- -- Model-Glue Sites: Home Page: http://www.model-glue.com Documentation: http://docs.model-glue.com Bug Tracker: http://bugs.model-glue.com Blog: http://www.model-glue.com/blog You received this message because you are subscribed to the Google Groups "model-glue" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/model-glue?hl=en--- You received this message because you are subscribed to the Google Groups "model-glue" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/groups/opt_out.
<<inline: compose-unknown-contact.jpg>>
<<inline: postbox-contact.jpg>>
<<inline: postbox-contact.jpg>>
