Skip to content
  • Jean Boussier's avatar
    62538743
    Make AbstractAdapter#lock thread local by default · 62538743
    Jean Boussier authored
    Fix: https://github.com/rails/rails/issues/45994
    
    A semi-common issue since Ruby 3.0.2 is that using a fiber inside
    a transaction cause a deadlock:
    
    ```ruby
    Post.transaction do
     enum =  Enumerator.new do |y|
       y.yield Post.first # stuck
     end
     enum.next
    end
    ```
    
    This is because in https://bugs.ruby-lang.org/issues/17827
    Ruby changed Monitor to be owned by the calling Fiber rather than Thread.
    
    And since the Active Record connection pool is per Thread, we end
    up in a situation where a Fiber tries to acquire a lock owned by another
    fiber with no change to ever resolve.
    
    In https://github.com/rails/rails/pull/46519
    
     We've made that lock optional
    as it's only needed for system tests.
    
    Now this PR introduce an alternative lock implementation that behave like Monitor
    used to up to Ruby 2.7, and we use this one if `ActiveSupport::IsolatedExecutionState.context`
    is a Thread.
    
    If it's a Fiber, we continue to use the implementation derived from the stdlib that is Fiber based.
    
    Co-Authored-By: default avatarMaple Ong <maple.develops@gmail.com>
    62538743
    Make AbstractAdapter#lock thread local by default
    Jean Boussier authored
    Fix: https://github.com/rails/rails/issues/45994
    
    A semi-common issue since Ruby 3.0.2 is that using a fiber inside
    a transaction cause a deadlock:
    
    ```ruby
    Post.transaction do
     enum =  Enumerator.new do |y|
       y.yield Post.first # stuck
     end
     enum.next
    end
    ```
    
    This is because in https://bugs.ruby-lang.org/issues/17827
    Ruby changed Monitor to be owned by the calling Fiber rather than Thread.
    
    And since the Active Record connection pool is per Thread, we end
    up in a situation where a Fiber tries to acquire a lock owned by another
    fiber with no change to ever resolve.
    
    In https://github.com/rails/rails/pull/46519
    
     We've made that lock optional
    as it's only needed for system tests.
    
    Now this PR introduce an alternative lock implementation that behave like Monitor
    used to up to Ruby 2.7, and we use this one if `ActiveSupport::IsolatedExecutionState.context`
    is a Thread.
    
    If it's a Fiber, we continue to use the implementation derived from the stdlib that is Fiber based.
    
    Co-Authored-By: default avatarMaple Ong <maple.develops@gmail.com>
Loading