Embedding everything inside a transaction

Hey Guys,

I've searched the depths of the world wide web for a solution to my problem with concurrent requests.

The problem is the following: In my App I initialize the user in a before_filter, with a bunch of included associations, processing cached columns yadda yadda. This takes some milliseconds. Enough to have some bad concurrent requests. For example (not a real scenario but describes the problem pretty well): A user is logged in in two browser tabs and fires two request or more at the same time. All requests are targetting the action "buy_the_item". The action checks if the user.money column has enough money and if yes, the item will be purchased. Now many requests are running in concurrent threads, and all have the same value of user.money ... so all the items get bought and the money column is saved from the thread that finishes last.

Ok how can I solve this? I'd like your opinions... I had some Ideas: - try loading the user in the filter with pessimistic locking (FOR UPDATE) ... Doesnt work. Found out that FOR UPDATE only works inside a transaction. damn. - starting a transaction inside the action and THEN reload everything i need with FOR UPDATE ... that would generate so much (to much) overhead. cause half of the requests deal with changing dependent table data. - place the WHOLE request inside one single transaction and do everything the normal way ... I'd like to try that... but how - any other ideas? Maybe someone faced a similar problem.

Thanks!!! Stefan

Hey Guys,

I've searched the depths of the world wide web for a solution to my problem with concurrent requests.

The problem is the following: In my App I initialize the user in a before_filter, with a bunch of included associations, processing cached columns yadda yadda. This takes some milliseconds. Enough to have some bad concurrent requests. For example (not a real scenario but describes the problem pretty well): A user is logged in in two browser tabs and fires two request or more at the same time. All requests are targetting the action "buy_the_item". The action checks if the user.money column has enough money and if yes, the item will be purchased. Now many requests are running in concurrent threads, and all have the same value of user.money ... so all the items get bought and the money column is saved from the thread that finishes last.

Ok how can I solve this? I'd like your opinions... I had some Ideas: - try loading the user in the filter with pessimistic locking (FOR UPDATE) ... Doesnt work. Found out that FOR UPDATE only works inside a transaction. damn. - starting a transaction inside the action and THEN reload everything i need with FOR UPDATE ... that would generate so much (to much) overhead. cause half of the requests deal with changing dependent table data. - place the WHOLE request inside one single transaction and do everything the normal way ... I'd like to try that... but how

an around_filter could do that for you.

- any other ideas? Maybe someone faced a similar problem.

I wrote up some approaches to similar problems here: Dealing with concurrency - Space Vatican

Fred

Frederick Cheung wrote:

Just figured that the approuch with the around_filter could turn out really awsome as it is a solution for another topic i have.

If you have user accounts and a support team, and want to have the support team able to log into the user accounts, but shouldnt be able to do any changes, this will come in very handy as well. You could raise an exception like "SupportTeamChangesNotAllowed" after the yield and everything would get rolled back. Even simple things like user.last_logged_in_at would be touched.

Just wanted to share the idea, think that can come in quite handy.