今天愉快的写 grape-api 时,忽然惊觉可能有线程安全问题!!我在 grape-issue 和 puma-issue 都发现了类似的提问。
根据 grape-issue 里的描述,他把服务器从 Unicorn 切换到 Puma 以后,发现 so much users get other users data from api。
他的代码是这样
base.rb
module V3
class Base < Grape::API
helpers V3Helpers
include V3::Photos
end
end
v3_helpers.rb
def current_user
return @current_user if defined? @current_user
@current_user = User.find(params[:uid])
end
photos.rb
module V3
module Photos
extend ActiveSupport::Concern
included do
resources :photos do
get do
photos = Photo.where(user_id: current_user.id)
photos.to_json
end
end
end
end
end
Base 的实例变量 @current_user
(我并不确定这个 @current_user
是否是 Base
的实例变量),似乎是被并发干扰了,很像 Java Servelet 里的线程安全的问题。
可我也正准备这么写呢,明明在 Rails 里这样用 @current_user
就 ok 啊。
我从 How Do I Know Whether My Rails App Is Thread-safe or Not? 里找到了为什么 Rails 里这样用是 ok 的。
In general, Rails creates a new controller object of every HTTP request, and everything else flows from there.
但是 Grape on Rails 里似乎是有线程安全问题的,那么如何解决呢?
我的想法是像下面这样避免使用 Instance Variable, 不知是否正确。如果是错误的,那么正确的方式又是什么呢?
v3_helpers.rb
def current_user
User.find(params[:uid])
end
photos.rb
module V3
module Photos
extend ActiveSupport::Concern
included do
resources :photos do
get do
user = current_user
photos = Photo.where(user_id: user .id)
photos.to_json
end
end
end
end
end