我的 Rails 4 + Devise 3.2 应用程序中的一项功能遇到了一个奇怪的问题,该功能允许用户通过 AJAX POST 将密码更改为以下操作,该操作源自 Devise wiki Allow users to edit their password。似乎在用户更改密码并在以后的一个或多个请求之后,他们被强制注销,并且在重新登录后将继续被强制注销。
# POST /update_my_password
def update_my_password
@user = User.find(current_user.id)
authorize! :update, @user ## CanCan check here as well
if @user.valid_password?(params[:old_password])
@user.password = params[:new_password]
@user.password_confirmation = params[:new_password_conf]
if @user.save
sign_in @user, :bypass => true
head :no_content
return
end
else
render :json => { "error_code" => "Incorrect password" }, :status => 401
return
end
render :json => { :errors => @user.errors }, :status => 422
end
此操作实际上在开发中运行良好,但当我运行多线程、多工作 Puma 实例时,它在生产中失败。Unauthorized
似乎发生的情况是,用户将保持登录状态,直到他们的请求之一到达不同的线程,然后他们以 401 响应状态注销。如果我使用单个线程和单个工作人员运行 Puma,则不会出现此问题。我似乎允许用户使用多个线程再次保持登录的唯一方法是重新启动服务器(这不是解决方案)。这很奇怪,因为我认为我拥有的会话存储配置会正确处理它。我的config/initializers/session_store.rb
文件包含以下内容:
MyApp::Application.config.session_store(ActionDispatch::Session::CacheStore,
:expire_after => 3.days)
我的production.rb
配置包含:
config.cache_store = :dalli_store, ENV["MEMCACHE_SERVERS"],
{
:pool_size => (ENV['MEMCACHE_POOL_SIZE'] || 1),
:compress => true,
:socket_timeout => 0.75,
:socket_max_failures => 3,
:socket_failure_delay => 0.1,
:down_retry_delay => 2.seconds,
:keepalive => true,
:failover => true
}
我正在通过bundle exec puma -p $PORT -C ./config/puma.rb
. 我的puma.rb
包含:
threads ENV['PUMA_MIN_THREADS'] || 8, ENV['PUMA_MAX_THREADS'] || 16
workers ENV['PUMA_WORKERS'] || 2
preload_app!
on_worker_boot do
ActiveSupport.on_load(:active_record) do
config = Rails.application.config.database_configuration[Rails.env]
config['reaping_frequency'] = ENV['DB_REAP_FREQ'] || 10 # seconds
config['pool'] = ENV['DB_POOL'] || 16
ActiveRecord::Base.establish_connection(config)
end
end
那么......这里可能出了什么问题?更改密码后,如何在不重新启动服务器的情况下更新所有线程/工作人员的会话?