Web Connection
How to prevent unwanted reentry into WC methods?
Gravatar is a globally recognized avatar based on your email address. How to prevent unwanted reentry into WC methods?
  Stein Goering
  All
  Jan 23, 2021 @ 10:03pm

Our app's checkout screen has a button that submits to myserver/payment.awp - which maps to the Payment method on our process object.

One of our customers is reporting occasional users submitting duplicate orders by clicking the button once, then again before the first process has completed. This despite having javascript in place to disable the button when it's first clicked - we frankly can't figure out how the hell the are doing this, but our transaction logs clearly show multiple instances of the Payment method running simultaneously in the same session. (FYI they are running under COM with multiple servers active.)

I'd like to add code on the back end to prevent that from happening. I thought something like this would work if coded at the outset of the method:

 lcPayStatus = Session.GetSessionvar('PayStatus')
 IF lcPayStatus = [INPROCESS]
   oUtil.HTMLMsg([Please Be Patient],[Payment is already in process])
   This.trace([PAY],[Starting checkout attempt when payment already in process]) && Generate Log entry
   RETURN
 ELSE
   This.trace([PAY],[Starting checkout process. Prior status: ]+lcPayStatus)
   SESSION.SetSessionVar([PayStatus], [INPROCESS])
 ENDIF
 This.trace([PAY],[PayStatus=]+Session.getsessionvar([PayStatus]))
* PayStatus will be cleared once the Payment process is completed

But this is not behaving as I expected. The logs verify that he PayStatus session var was explicitly set to "INPROCESS" the first time the Payment method runs. But when the second instance of the method is invoked, PayStatus comes up blank again - it's somehow not recognizing the fact the INPROCESS setting.

Is there some buffering going on here? If so, is there a way to work around it? Another approach that would prevent launching a second instances of the Payment method until the first one is completed?

--stein

Gravatar is a globally recognized avatar based on your email address. re: How to prevent unwanted reentry into WC methods?
  FoxInCloud Support - Thierry N.
  Stein Goering
  Jan 24, 2021 @ 12:29am

By default, the wwSession table gets updated when transaction completes, and session is closed (changes held in this.oData until then)

You need to save changes right away.

Gravatar is a globally recognized avatar based on your email address. re: How to prevent unwanted reentry into WC methods?
  Marcel DESMET
  FoxInCloud Support - Thierry N.
  Jan 24, 2021 @ 01:03pm

Hello, we had the same problem after switching to COM mode As pointed out you have to add SESSION.Save().

Gravatar is a globally recognized avatar based on your email address. re: How to prevent unwanted reentry into WC methods?
  Rick Strahl
  Stein Goering
  Jan 24, 2021 @ 02:04pm

As Thierry points out there's a possibility of multiple clicks causing multiple requests to process 'simultaneously'.

As suggested using Session.Save() explicitly and then making sure you check the session vars before every Save() operation can help, but even that's no guarantee if two requests are running literally side by side.

The only way you can really prevent that is by using a 'locking' variable (semaphore) that you check before the transaction and that is set before you enter the transaction.

  • Check for the 'lock variable' in session table
  • If it exists - it's busy, don't allow
  • If it doesn't exist - create one and save
  • Now run your processing
  • When done remove the Session var

The value you save works best if it's a timestamp of some sort so if for some reason the remove operation doesn't happen it doesn't prevent you from saving. So you check for existence and for a certain timeout period (probably a few seconds only).

This makes the Session 'save' operation really small and atomic (basically a single value save operation) so there's very little (but still not 100%!) chance that you run into a truly simultaneous transaction.

Frankly I've never run into a scenario where apps are too busy to cause that kind of contention - even with accidental multi-clicks. For most apps it's sufficient to explicitly check before saving that the data wasn't already saved (with a timestamp preferably). If you see that the order was already saved within the last few seconds you can assume it's a dupe. This is a good data practice anyway for any data that may have contention.

Also, I tend to write my apps in such a way that multiple saves even if it does happen won't break things. If an order gets saved twice it should be repeatable so that even a if another save occurs it wouldn't actually break anything. In most applications there are a only a few places where this even applies (ie. where multiple users edit the same data).

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: How to prevent unwanted reentry into WC methods?
  Stein Goering
  Rick Strahl
  Feb 1, 2021 @ 08:04pm

I should note that adding Session.save() at a couple of crucial points resolved my problem. Thanks to everyone who responded.

--stein

© 1996-2021