User sessions invalid after password change, but with only a few threads

I had a strange problem with the function of my Rails 4 + Devise 3.2 application, which allows users to change their password through AJAX POST for the next action, obtained from the Devise wiki Allow users to edit their password . It seems that after the user changes his password and after one or more requests later, they will be forced to log out of the system and will continue to force logout after logging in.

# 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)

My 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
}

puma 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

... ? / ?

+4
4

, , , ActiveRecord User .

, ActiveRecord, User.rb:

# this default scope avoids query caching of the user,
# which can be a big problem when multithreaded user password changing
# happens. 
FIXNUM_MAX = (2**(0.size * 8 -2) -1)
default_scope { 
  r = Random.new.rand(FIXNUM_MAX)
  where("? = ?", r,r)
}

, , , , , . , , . , /.

0

Dalli , .

Dalli

:

" Puma , Dalli 2.7, Dalli Rails, , Rails.cache ."

+2

, - :

  • devise current_user, , . lib/devise/controllers/helpers.rb # 58.

    def current_#{mapping}
      @current_#{mapping} ||= warden.authenticate(:scope => :#{mapping})
    end
    

, , , , . , _ - , , , .

( ), . , , , . , , , .

+1

, , , , :

  def update_password
    @user = User.find(current_user.id)
    if @user.update(user_params)
      sign_out @user # Let them sign-in again
      reset_session # This might not be needed?
      redirect_to root_path
    else
      render "edit"
    end
  end

, , sign_in , .

0

Source: https://habr.com/ru/post/1525133/


All Articles