我在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。我的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
所以...这里可能出什么问题了?更改密码后,如何在所有线程/工作人员之间更新会话,而无需重新启动服务器?
我在Rails 4 + Devise 3.2应用程序中遇到了一个奇怪的问题,该应用程序允许用户通过AJAX POST将其密码更改为从Devise派生的以下操作...
由于您使用Dalli作为会话存储,因此您可能会遇到此问题。
我怀疑您由于以下问题而看到这种行为:
我建议用户更改密码后,注销并清除会话,就像这样:
这是一个总的总的解决方案,但是看来其他线程将执行我的ActiveRecord query caching模型的User
,并且返回的陈旧数据将触发身份验证失败。
我正面临类似的问题,是否有人对此有适当的解决方法。