Application Crashes Due to Duplicated Concurrent INSERT Transactions [message #5886] |
Tue, 20 September 2016 01:25 |
kong
Messages: 90 Registered: December 2011
|
Member |
|
|
This is further on the issue that was brought up here http:// radicore.org/fud/index.php?t=msg&th=2283&goto=5883&a mp;a mp;a mp;a mp;#msg_5883
Multiple submits of the same ADD1 forms will lead to concurrent INSERT transactions in the database. If the table uses non auto-increment primary keys or has other unique key constraints, this could result in fatal error thrown by the database (in this case MySQL) and application crash.
The checks built into the framework as described here http:// www.tonymarston.net/php-mysql/functions-and-variables.html#n otes._dml_insertrecord should have prevented such crash and presented the user with user-friendly error messages instead. However, under certain race conditions which are hard to replicate, multiple submits of the same form in rapid succession could result in concurrent transactions invoked by calling startTransaction() function followed by insertRecord() method in the controller script for every click on the submit button. If you are unlucky, you could end up with these concurrent insertRecord transactions all working off the same pre-transaction snapshot of the database table and hence each transaction passing the above mentioned framework built-in checks without raising any errors, until one transaction has been committed successfully but then is followed by another transaction's INSERT which in turn makes the database throw a Duplicate Key Fatal Error, crashing the application.
To solve this problem, there are several options I can think of:
1) Explicitly set database table lock before the transaction starts by customizing _cm_getDatabaseLock() for every table with non auto-increment primary key or other unique keys.
2) Use a hidden field token to guard against multiple submissions of the same form, for example as shown in http://docstore.mik.ua/orelly/webprog/pcook/ch09_06.htm and http://phpsense.com/2006/prevent-duplicate-form-submission/.
3) Since we are relying on the framework for validations and unique key constraint checking anyway, we might as well use a different SQL insert command that does not throw Unique Key Fatal Errors on insert. For example in MySQL use INSERT IGNORE instead of INSERT.
4) Temporary lower the Isolation Level for Transactions in the database before the transaction begins. For example, in MySQL, lower from default level 3 'REPEATABLE READ' to level 1 'READ UNCOMMITTED'.
In my case I am using option 3 as that is least amount of work. But for the long run and improving robustness of the framework I think the 2nd option could be worth some effort.
[Updated on: Tue, 20 September 2016 04:01] Report message to a moderator
|
|
|
Re: Application Crashes Due to Duplicated Concurrent INSERT Transactions [message #5888 is a reply to message #5886] |
Tue, 20 September 2016 05:59 |
AJM
Messages: 2368 Registered: April 2006 Location: Surrey, UK
|
Senior Member |
|
|
Firstly, you should train your users not to keep repeatedly pressing the submit button in the hope that it will make things go faster. This issue is not limited to the Radicore framework as it is eactly the same for *ALL* web applications.
Secondly, you are missing an option. I have seen some websites which, when a submit button is pressed, use javascript to disable the button. The button is not enabled until the operation started by that button is completed and the form is refreshed.
Thirdly, using an option which requires comparing a value in the form with a value stored in the session data would still not be foolproof as the second submission could read the session data before the first submission has updated it.
In all the years that the Radicore framework has been used this issue has never appeared. It sounds like the only sure-fire option would be to lock the entire table before each unsert so that concurrent inserts are then impossible. However, the side effect of this would be to slow down the system for all those users who are adding records to the same table.
Tony Marston
http://www.tonymarston.net
http://www.radicore.org
|
|
|
|
|
|
|
|
|
Re: jQuery Solution: Application Crashes Due to Duplicated Concurrent INSERT Transactions [message #5956 is a reply to message #5950] |
Fri, 07 October 2016 03:17 |
kong
Messages: 90 Registered: December 2011
|
Member |
|
|
As reference, here is a good description of the cause of the problem related to downloads in general: http:// gruffcode.com/2010/10/28/detecting-the-file-download-dialog- in-the-browser/
In short: For any actions that do not result in a page refresh or redirect, we need to make use of a temporary cookie, which when detected in the browser will trigger jQuery to clean up the screen (meaning get rid of previous spinners and re-enable buttons).
Here are the steps to implement this update:
1) Download and extract 2 files from the attachment. An updated custom_javascript.class.inc and a new file jquery.cookie.min.js which should be saved in the radicore/javascript folder.
2) In std.output1.inc and std.output4.inc, find this line of code:header("Content-type: text/comma-separated-values"); and change it to:setcookie('clean_up_screen_' . session_name(), $GLOBALS['task_id'], time()+30);
header("Content-type: text/comma-separated-values"); When these transactions are activated they will set a 30 seconds cookie by session_name and by controller path upon start of download, which is the signal for the browser to clean up the screen without the need for screen refresh. The cookie will be deleted after each clean up. So far, I have only identified these 2 patterns that need this fix. Please let me know of other transaction patterns that also do not result in page reloads or redirects, as those will need similar fix as well.
I have checked this on
Chrome 53
Firefox 49
Waterfox 48
IE 11
-
Attachment: fix_csv.7z
(Size: 2.12KB, Downloaded 931 times)
|
|
|
|