Skip to content
  • Jean Boussier's avatar
    7fc174aa
    Allow Adapter#select_all to be performed asynchronously from a background thread pool · 7fc174aa
    Jean Boussier authored
    Sometimes a controller or a job has to perform multiple independent queries, e.g.:
    
    ```
    def index
      @posts = Post.published
      @categories = Category.active
    end
    ```
    
    Since these two queries are totally independent, ideally you could
    execute them in parallel, so that assuming that each take 50ms, the
    total query time would be 50ms rather than 100ms.
    
    A very naive way to do this is to simply call `Relation#to_a` in a
    background thread, the problem is that most Rails applications, and
    even Rails itself rely on thread local state (`PerThreadRegistry`,
    `CurrentAttributes`, etc). So executing such a high level interface
    from another thread is likely to lead to many context loss problems
    or even thread safety issues.
    
    What we can do instead, is to schedule a much lower level operation
    (`Adapter#select_all`) in a thread pool, and return a future/promise.
    This way we kepp most of the risky code on the main thread, but perform
    the slow IO in background, with very little chance of executing some
    code that rely on state stored in thread local storage.
    
    Also since most users are on MRI, only the IO can really be parallelized,
    so scheduling more code to be executed in background wouldn't lead
    to better performance.
    7fc174aa
    Allow Adapter#select_all to be performed asynchronously from a background thread pool
    Jean Boussier authored
    Sometimes a controller or a job has to perform multiple independent queries, e.g.:
    
    ```
    def index
      @posts = Post.published
      @categories = Category.active
    end
    ```
    
    Since these two queries are totally independent, ideally you could
    execute them in parallel, so that assuming that each take 50ms, the
    total query time would be 50ms rather than 100ms.
    
    A very naive way to do this is to simply call `Relation#to_a` in a
    background thread, the problem is that most Rails applications, and
    even Rails itself rely on thread local state (`PerThreadRegistry`,
    `CurrentAttributes`, etc). So executing such a high level interface
    from another thread is likely to lead to many context loss problems
    or even thread safety issues.
    
    What we can do instead, is to schedule a much lower level operation
    (`Adapter#select_all`) in a thread pool, and return a future/promise.
    This way we kepp most of the risky code on the main thread, but perform
    the slow IO in background, with very little chance of executing some
    code that rely on state stored in thread local storage.
    
    Also since most users are on MRI, only the IO can really be parallelized,
    so scheduling more code to be executed in background wouldn't lead
    to better performance.
Loading