• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
0

Problem with rapid successive submit button presses

Enthusiast ,
Sep 03, 2009 Sep 03, 2009

Copy link to clipboard

Copied

I have set up a CF shopping process which integrates into PayPal, using session variables along the way.

I appear to have stumbled across a problem whereby if the final submit button is pressed rapidly or I manually hit the URL using the enter key from the url bar, real quick, that I run into an issue.

What appears to happen is that the sessions, which you would expect to have been created on the first hit to the page which was technically not visible due to the rapid 2nd submit, do not seem to be there, certainly not quick enough to be handled in the 2nd hit.

I have a script in there that looks for removal of certain session variables so that I don't end up writing two records in the dbase. I see that by checking the dbase that the initial records are indeed written to the dbase, but the sessions just don't appear quick enough

Ultimately what I experience if a CFerror that the variables that are expected to display on the page confirming the order number etc..etc just don't exist.

Anybody got any thoughts on handling issues like this?

Thanks

Mark

TOPICS
Advanced techniques

Views

1.5K

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Sep 04, 2009 Sep 04, 2009

Copy link to clipboard

Copied

On the client, you can write some javascript to disable or hide the submit button when the form is submitted.  We have something like that, but if you try hard enough, you can defeat it.

On the server, you can do a couple of things.  You can submit to an intermediate page which converts the form variables to session variables and forwards the user to the real page.  Or, you can cfflush some text onto the real page and then start processing.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Sep 04, 2009 Sep 04, 2009

Copy link to clipboard

Copied

Hi dan

Thanks for the reply. I did actually try the intermediate page approach, and unfortunately it did not work, if I was quick enough I can easily start two sessions for the same person.

As you said the javascript can be bypassed

I did a little research and would have posted it earlier but the forum went down after I made my initial post.

What I foundwas that a CFLOCK appeared to do the trick, I put a CFLOCK around the whole page which performs the processing and after testing many times I have not managed to trip it. I've never used CFLOCK before, I'm wondering if there are any negative effects to this approach.

Here's the code i used, as you can see I made the scope SESSION, I presume that otherwise it might lock out other users

<cflock timeout = "999"
scope = "Session"
throwOnTimeout = "No"
type = "exclusive">

Thanks

Mark

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Sep 04, 2009 Sep 04, 2009

Copy link to clipboard

Copied

scrub the answer below, I gave it another test this morning and I managed to trip it immediately, I guess I was slowing down on the button pressing last night!

Mark

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Sep 04, 2009 Sep 04, 2009

Copy link to clipboard

Copied

In my opinion, you did correctly diagnose the cause of the problem, namely, race conditions. I am assuming you configured your application properly (sessionManagement, sessionTimeOut, etc). Then there would just be one session for the client. Not sessions in plural, as you suggest.

The race conditions would then have been caused by two requests that attempted to access the same block of session-scoped code. A lock is indeed the answer. I would use a lock timeout of between 5 and 30 seconds, certainly not 999.

However, there is another possible problem. Coldfusion needs a finite amount of time to clear the deleted session variables from memory. If you fired two requests in quick succession while that was going on, you could indeed initiate new sessions.

An undeleted session variable is no big problem. Accidentally triggering a new session is. A new session means a new client or a new order. You wouldn't want your application to begin a new session halfway through a current one, or to end the current one prematurely. So pay particular attention where you delete the session variables, especially Coldfusion's session cookies.

You almost certainly shouldn't do that upon submission of a form. Validate the form on the action page. Invalid data should halt execution.

You would normally delete session variables on the logout page. The cflogout tag, coupled with <cflogin> and the setting loginStorage="session", would prevent any inconsistencies..

Nevertheless, without some code, this all amounts to speculation.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Sep 05, 2009 Sep 05, 2009

Copy link to clipboard

Copied

Thanks for the in-depth reply.

This is what I use to initiate the session

<cfapplication
    sessionmanagement="yes"
    name="myapp"
    sessionTimeout="#createTimeSpan(0,0,30,0)#"
        />

I thought the CFLOCK worked but the next day I was able to trip it, however, now I'm not able to do so, weird, I think the shared server that I had this on was possibly running slow at the time so the SQL was not responding quickly and therefore allowing me to get that extra hit in.

I'm using this session for a purchase, the final page displays an invoice and creates necessary records inside the database. I use a single session variable to let CF know if I require the code to post a payment request to PayPal, after which I delete that variable, but allow all others to remain, that way, if the user refreshes the page it can still display the info including their log in information. I did this with the thought that if there was a delay/pause in displaying the page and they hit submit again, it would not recharge them but it would also allow them to obtain their info and make it look like a successful order.

However, as described, I was able to rapidly hit the button, in such a way that the session variable which tells the CF to process not to post a payment did indeed seem to have been set to zero, but the other session variables obtained from the queries did not exist, which resulted in a problem because the refresh did not have the sessions available to display the page correctly.

The code which clears out the session to tell it not to post a payment/dbase write again had to go close to the top because the payment to PayPal was the first thing processed, then my local dbase queries follow, if I did not put the session variable removal right underneath the paypal post, it could potentially try to double bill them, althought paypal would reject the token (I would hope) even with rapid posting, I did not want to take the risk.

I can't have a log out option because they are not technically logged into an account.

Hope that explains

Thanks

Mark

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Sep 05, 2009 Sep 05, 2009

Copy link to clipboard

Copied

You could do it in a lock, like this

<cflock timeout = "10" scope = "Session" throwOnTimeout = "No" type = "exclusive">

<!--- validate form data --->

<!--- do any pre-transaction database business --->

<!--- assign value to session.doPayPal to enable PayPal transaction --->

<!--- do the PayPal transaction --->

<!--- do any post-transaction database business --->

<!--- reassign value to session.doPayPal to disable PayPal transaction --->

</cflock>

If the code is too long or too involved, you could split it up into blocks within locks that share the same name.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Sep 05, 2009 Sep 05, 2009

Copy link to clipboard

Copied

Thanks again.

I'm going to have to go back and study the code. There are several dbase inserts which create an account for them, record the transaction and also create software license(s). My other concern was that if there was a crash along the way and it did not get to the payment, that they could potentially still have their records written, which would amount to them getting a license at no charge.

Mark

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Oct 01, 2009 Oct 01, 2009

Copy link to clipboard

Copied

Normal practice would be to start a session BEFORE you start processing form results, where does the form come from, is it NOT on your server?

If it IS on your server, start a session once the form page is requested and process session form submit only once, i.e. in processing page check if the session is already flagged as processing/processed and set processing flag in a session if it is NOT...

Once the payment confirmation is received set the processed flag too...

Or did I misunderstand something?

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Oct 01, 2009 Oct 01, 2009

Copy link to clipboard

Copied

LATEST

that is pretty much how I did it, set a session variable to say that the payment session was active, and then once I processed it, set it to zero, but retain all of the other info, so I could display their invoice etc, therefore if they hit the button twice, real quick they would not know the difference

The only problem I see now is that if PayPal does not connect for any reason I need to catch the error and warn the user, or retry, I tried various CF methods but could not get my brain around them

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Resources
Documentation