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: http://www.spacevatican.org/2008/6/8/dealing-with-concurrency

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.