Example of something that is not thread-safe in Rails

本秂侑毒 提交于 2019-12-21 04:34:09

问题


I've seen threads like this on thread-safety in Rails and various web pages on the topic, and I'm sure everyone's great at reciting what it is and giving 'tips' on what isn't thread-safe ("class variables!"), but I can never seem to find a clear, simple, complete example of something that is actually not thread-safe in Rails, to the point where I wonder if anyone actually understands it at all.

I would be grateful if someone could prove me wrong and give:

  • a clear, simple, complete example of something that is not thread-safe in Rails. It should be clear where the code is (i.e., if it is in the controller, please show it as such) and nothing should be left to the reader's imagination (such as a method that doesn't exist). Also, there shouldn't be any superfluous code or logic.

  • exactly how it would be problematic in the context of two users connecting to the website at the same time, on two different threads.

  • how to rectify the problem.

The more significant and Rails-relevant the example, the better, so if you can give an example where one user might see another user's data (or similar), please do so.


回答1:


NOTE
This is only a partial answer since it's a stale read example (which can be caused by both multiprocesses and multithreading), the OP is looking for multithreading issues only it seems.

Here goes, imagine you have a store that sells an item to a user and updates his balance accordingly.

 PaymentsController

    if current_user.balance > item.price 
       current_user.balance = current_user.balance - item.price #1
       current_user.create_purchase(item)  #2
       current_user.save #3
    end

The potential problem here is that inside the condition (lets say in lines #1 or #2) the thread can switch to a different thread, run fully, the balance is now a different value yet when we return to the original thread (still stuck in line #1) it has no idea this has happened! It may allow a purchase for a user with not enough balance and it also override the real balance with a wrong value.

Here's a more concrete example of how this can happen

Let's imagine the user is trying to game our system by buying more than his balance allows him. Item 1 costs 100, Item 2 costs 75 and his balance is 100.

The user writes a script to fire 2 posts requests to purchase these items so they get almost simultaneously to the app server. The first requests hits line #1, and right before line #2 the thread switches to request 2. The second request runs fully with no interruption - it buys the second item so the new real balance is now 25 (100 - 75). Now the context switch to request 1. Request 1 does not realize that the real balance is 25 (it still thinks that the user had enough balance to buy the item: remember that request 1 switched at line #2, inside the condition! Request 1 completes the purchase and then updates the balance to be 0 (100 - 100). The user just bought two products that cost more than his balance should allow!

A way to handle this situation is locking http://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html



来源:https://stackoverflow.com/questions/38587612/example-of-something-that-is-not-thread-safe-in-rails

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!