ruby-on-rails - 更改密码后用户 session 无效,但仅限于多线程

标签 ruby-on-rails multithreading devise ruby-on-rails-4 puma

我在 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,则不会出现此问题。我似乎允许用户使用多个线程再次保持登录状态的唯一方法是重新启动服务器(这不是解决方案)。这很奇怪,因为我认为我的 session 存储配置会正确处理它。我的 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 .我的 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

那么......这里可能出了什么问题?当密码更改时,如何在不重新启动服务器的情况下更新所有线程/ worker 的 session ?

最佳答案

由于您使用 Dalli 作为 session 存储,因此您可能会遇到此问题。

Multithreading Dalli

从页面:

“如果您使用 Puma 或其他线程应用服务器,从 Dalli 2.7 开始,您可以使用带有 Rails 的 Dalli 客户端池来确保 Rails.cache 单例不会成为线程争用的来源。”

关于ruby-on-rails - 更改密码后用户 session 无效,但仅限于多线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21540085/

相关文章:

ruby-on-rails - RVM 安装错误

ruby-on-rails - 设计无密码更新用户

c++ - 在一种方法中使用两个 boost 互斥体?

ruby-on-rails - 用户只能从一个帐户登录三台设备

ruby-on-rails - rails 验证嵌套属性

ruby-on-rails - Rails服务器启动/停止

c++ - C++ 中的多线程矩阵乘法

java - 为什么足够的同步边集是唯一的以及如何构建它?

ruby-on-rails - heroku 使用 Devise 部署 NameError

ruby-on-rails-3 - 还有什么其他方法可以用 Cucumber 测试 Devise 'not logged in'?