4 Replies Latest reply on Mar 9, 2013 5:24 AM by BKBK

    Securing CFC Variables Under Load

    Pete L. Level 1

      I've been using CFC's for processing for a little while now and haven't come across this issue before as most of our applications run internally and don't get much load. I have an application running now that processes payments online for renters and since they are all due on the first of each month, there's a ton of activity for 1-2 days and then it dies off again. I noticed the last time this was heavily used (March 1) that when then 2 or more people are paying online in very close time proximity to each other, the data I'm capturing to record the payments is missed up, and often related to the payment information directly before or after the incorrect one. It's like when someone else enters the CFC, it's over-writing some of the variables within the CFC.

       

      Here's some of the code (simplified):

      1. I'm setting the CFC's and some other variables into the application scope in Application.cfm on start of the application:

           <cfif IsObject(application.commonCFC) EQ false OR URL.init NEQ "">

               <cflock type="exclusive" timeout="30">

                    <cfset application.commonCFC = createObject("component","assets/cfc/common")>

               </cflock>

           </cfif>

      2. A user fills out a form on a page and submits the payment data back to the same page.

      3. I'm setting the payment amount and formatting it:

           <cfset pmtTotal = NumberFormat(form.pmtAmt, "99.99")>

      4. I post it to the CFC:

           <cfset postPayment = application.commonCFC.postCCPayment('#session.accountNum#','#form.ccNum#','#pmtTotal#')>

      5. In the CFC, I've wrapped the body of it in a cftransaction block to try to prevent multiple executions at the same time.

      6. After that, I'm setting some variables in the CFC:

           <cfset pmtAmt = arguments.pmtAmt>

           <cfset feesAmt = 0>

           <cfset totalAmt = NumberFormat((pmtAmt + feesAmt), "99.99")>

      7. Then submit it to the payment gateway.

      8. Then capture the results in a database table, including the pmtAmt, feesAmt, and totalAmt.

       

      What I notice is that in the database capture (the last thing to execute), the feesAmt and totalAmt are not correct once in a while (usually when 2 transactions are very close together). I'm assuming the pmtAmt IS correct becuase it matches what was captured by the processor and matches the amount due for the tenant. I notice this by running a quick query that pulls records if the pmtAmt + feesAmt <> totalAmt. I did have the variables in the cfc set to <cfset var xxxx.../> previously, but had to take this out when I added the cftransaction tag as they weren't immediately following the cfarguments then (I'm on CF8).

       

      Why would the other variables be changing mid-stream? How can I prevent this? I need essentialy single-user access to this process until the function is done. I've thought about cflock, but have had trouble with that in the past with people getting locked out and not being able to obtain the lock. There has to be a simpler way.

       

      Thanks for any help!

        • 1. Re: Securing CFC Variables Under Load
          duncancumming Level 3

          Are you certain you're var-scoping everything in your functions?  That's usually the one area most likely to cause this kind of problem in my experience.  http://varscoper.riaforge.org/ is useful although won't detect everything (and also returns false negatives)

          • 2. Re: Securing CFC Variables Under Load
            Pete L. Level 1

            Thanks - I had the main things var-scoped before, but took that out with the cftransaction thing. Should I take out the cftransaction now and then var-scope EVERYTHING in the CFC? Will that prevent 2 people from running the function at the same time and over-writing the variables as they go? I guess I could also var-scope the vairables and then have the cftransaction block start.

            • 3. Re: Securing CFC Variables Under Load
              duncancumming Level 3

              I think I'd var-scope everything and keep the cftransaction in there, and not worry about those variables being initialised before your transaction.

              • 4. Re: Securing CFC Variables Under Load
                BKBK Adobe Community Professional & MVP

                I think that your code can be simplified. Here are some things you might want to consider.

                 

                <cfif IsObject(application.commonCFC) EQ false OR URL.init NEQ "">

                         <cflock type="exclusive" timeout="30">

                              <cfset application.commonCFC = createObject("component","assets/cfc/common")>

                         </cflock>

                     </cfif>

                <!--- Application lock unnecessary here--->

                <cfif NOT isDefined("application.commonCFC") OR URL.init NEQ "">

                <cfset application.commonCFC = createObject("component","assets.cfc.common")>

                </cfif>

                 

                2. A user fills out a form on a page and submits the payment data back to the same page.

                3. I'm setting the payment amount and formatting it:

                     <cfset pmtTotal = NumberFormat(form.pmtAmt, "99.99")>

                <!--- To each, his own pmtTotal. --->

                <cfset session.pmtTotal = NumberFormat(form.pmtAmt, "99.99")>

                 

                4. I post it to the CFC:

                     <cfset postPayment = application.commonCFC.postCCPayment('#session.accountNum#','#form.ccN um#','#pmtTotal#')>

                <cfset session.postPayment = application.commonCFC.postCCPayment(session.accountNum,form.ccNum,session.pmtTotal)>

                 

                5. In the CFC, I've wrapped the body of it in a cftransaction block to try to prevent multiple executions at the same time.

                Unnecessary. Delete the cftransaction tags, if that is all you use them for. The cftransaction tag is meant to send instructions to the database engine, not to ColdFusion.

                 

                6. After that, I'm setting some variables in the CFC:

                     <cfset pmtAmt = arguments.pmtAmt>

                     <cfset feesAmt = 0>

                     <cfset totalAmt = NumberFormat((pmtAmt + feesAmt), "99.99")>

                Var-scope the first occurrence of any local variable within a function. For example,

                 

                <cfset var pmtAmt = ...>

                <cfset var feesAmt =...>

                <cfset var totalAmt = ...>

                 

                Suppose you wish to use any result from the CFC on a CFM page. Then, in the CFM page, create an instance of the CFC and use it to call a function that returns the result you want.