-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add #route_to_readyset Method to Readyset::ControllerExtension for Re…
…plica DB Routing (#28) ## Overview This pull request introduces the route_to_readyset method into the Readyset::ControllerExtension module. This method provides the functionality to route queries in specified controller actions to a replica database. It basically just changes the context of where it's running by using [#connected_to](https://apidock.com/rails/v6.0.0/ActiveRecord/ConnectionHandling/connected_to). ## Changes > Added the route_to_readyset method. > The method accepts a list of actions and options to determine where and how database routing should be applied. > It employs the around_action callback in controllers to wrap specified actions. > Inside the callback, the ActiveRecord connection is switched to a replica database. ## Usage Developers can use route_to_readyset in their controllers to specify actions that should route their queries to a replica database. The method accepts action names and additional options like :only and :except to refine the callback application. ## Documentation YARD documentation has been added to describe the method's purpose, parameters, and usage. Work-in-progress. I've basically only used YARD for ViewComponent docs. ## Notes - Future enhancements might include decoupling the database role symbol to allow configuration-driven role specification. - Improve the spec to account for all the possible parameters - Allow single-query re-routing In regards to other features: - Flagged queries could be tagged during re-routing - Said queries could be sent to a log/reference file of queries that are flagged but not yet specified in the "cache migration" file. Maybe be possible to use this file to auto-fill any areas in the cache migration like "controller#action -> grabs logged queries from file that came from this action". ## Example ```ruby class PostsController < ApplicationController include Readyset::ControllerExtension route_to_readyset :index, only: [:index, :show] end ``` In this example, queries in the index and show actions of the PostsController will be routed to the replica database.
- Loading branch information
1 parent
ce01a82
commit df6b396
Showing
22 changed files
with
305 additions
and
70 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
--format documentation | ||
--color | ||
--require spec_helper | ||
--require rails_helper |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'rubygems' | ||
require 'bundler' | ||
|
||
Bundler.require :default, :development | ||
|
||
Combustion.initialize! :all | ||
run Combustion::Application |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,34 +1,20 @@ | ||
# lib/readyset.rb | ||
|
||
require 'readyset/configuration' | ||
require 'readyset/default_resolver' | ||
require 'readyset/controller_extension' | ||
require 'readyset/middleware' | ||
require 'readyset/query' | ||
require 'readyset/railtie' if defined?(Rails::Railtie) | ||
|
||
require 'active_record' | ||
|
||
module Readyset | ||
attr_writer :configuration | ||
|
||
def self.configuration | ||
@configuration ||= Configuration.new | ||
end | ||
|
||
def self.configure | ||
yield(configuration) | ||
end | ||
|
||
def self.current_config | ||
configuration.inspect | ||
end | ||
|
||
# Executes a raw SQL query against ReadySet. The query is sanitized prior to being executed. | ||
# | ||
# @param [Array<Object>] *sql_array the SQL array to be executed against ReadySet | ||
# @return [PG::Result] | ||
def self.raw_query(*sql_array) | ||
ActiveRecord::Base.establish_connection(Readyset.configuration.connection_url) | ||
ActiveRecord::Base.establish_connection(Readyset::Configuration.configuration.database_url) | ||
ActiveRecord::Base.connection.execute(ActiveRecord::Base.sanitize_sql_array(sql_array)) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
module Readyset | ||
# Module providing controller extensions for routing ActiveRecord queries to a replica database. | ||
module ControllerExtension | ||
extend ActiveSupport::Concern | ||
|
||
prepended do | ||
# Sets up an `around_action` for a specified set of controller actions. | ||
# This method is used to route the specified actions through Readyset, | ||
# allowing ActiveRecord queries within those actions to be handled by a replica database. | ||
# | ||
# @example | ||
# route_to_readyset only: [:index, :show] | ||
# route_to_readyset :index | ||
# route_to_readyset except: :index | ||
# route_to_readyset :show, only: [:index, :show], if: -> { some_condition } | ||
# | ||
# @param args [Array<Symbol, Hash>] A list of actions and/or options dictating when the | ||
# around_action should apply. | ||
# The options can include Rails' standard `:only`, `:except`, and conditionals like `:if`. | ||
# @yield [_controller, action_block] An optional block that will execute around the actions. | ||
# Yields the block from the controller action. | ||
# @yieldparam _controller [ActionController::Base] Param is unused. | ||
# @yieldparam action_block [Proc] The block passed along with the action. | ||
# | ||
def self.route_to_readyset(*args, &block) | ||
around_action(*args, *block) do |_controller, action_block| | ||
Readyset.route do | ||
action_block.call | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
# spec/readyset/controller_extension_spec.rb | ||
|
||
require 'readyset/controller_extension' | ||
|
||
RSpec.describe Readyset::ControllerExtension, type: :controller do | ||
# Global Set-up | ||
controller(ActionController::Base) do | ||
# Main point-of-interest in our fake controller | ||
# This line specifies that these queries will be re-routed | ||
route_to_readyset only: [:index, :show] | ||
|
||
def index | ||
@posts = Post.where(active: true) | ||
render plain: 'Index' | ||
end | ||
|
||
def show | ||
@post = Post.find(params[:id]) | ||
render plain: 'Show' | ||
end | ||
|
||
def create | ||
Post.create(params[:post]) | ||
render plain: 'Create' | ||
end | ||
end | ||
|
||
before do | ||
# Need a way to clean this up | ||
routes.draw do | ||
get 'index' => 'anonymous#index' | ||
get 'show/:id' => 'anonymous#show' | ||
post 'create' => 'anonymous#create' | ||
end | ||
|
||
# Our fake queries | ||
stub_const('Post', Class.new) | ||
allow(Post).to receive(:where).and_return([]) | ||
allow(Post).to receive(:find).and_return(nil) | ||
allow(Post).to receive(:create) | ||
|
||
allow(Readyset).to receive(:route).and_yield | ||
end | ||
|
||
describe '#route_to_readyset' do | ||
before do | ||
allow(controller.class).to receive(:around_action) | ||
end | ||
|
||
def expect_around_action_called_with(*expected_args, &block) | ||
expect(controller.class).to have_received(:around_action).with(*expected_args, &block) | ||
end | ||
|
||
context 'when delegating to around_action' do | ||
it 'delegates arguments unchanged to around_action' do | ||
# Arguments based off of _insert_callbacks | ||
# callbacks | ||
action = :test_action | ||
options_hash = { only: [:index, :show] } | ||
|
||
# optional block | ||
test_block = proc { 'test block content' } | ||
|
||
controller.class.route_to_readyset(action, options_hash, &test_block) | ||
|
||
expect_around_action_called_with(action, options_hash, test_block) do |&block| | ||
expect(block).to eq(test_block) | ||
end | ||
end | ||
end | ||
|
||
context 'with a single action' do | ||
it 'passes a single action symbol to around_action' do | ||
controller.class.route_to_readyset :index | ||
expect_around_action_called_with(:index) | ||
end | ||
end | ||
|
||
context 'with only option' do | ||
it 'passes :only option with multiple actions to around_action' do | ||
controller.class.route_to_readyset only: [:index, :show] | ||
expect_around_action_called_with(only: [:index, :show]) | ||
end | ||
end | ||
|
||
context 'with except option' do | ||
it 'passes :except option to around_action' do | ||
controller.class.route_to_readyset except: :index | ||
expect_around_action_called_with(except: :index) | ||
end | ||
end | ||
|
||
context 'with multiple options and a block' do | ||
it 'accepts multiple options and a block' do | ||
block_conditional = proc {} | ||
|
||
controller.class.route_to_readyset :show, only: [:index, :show], if: block_conditional | ||
|
||
expect_around_action_called_with(:show, { only: [:index, :show], if: block_conditional }) | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
test: | ||
adapter: sqlite3 | ||
database: db/combustion_test.sqlite |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# frozen_string_literal: true | ||
|
||
Rails.application.routes.draw do | ||
# Add your own routes here, or remove this file if you don't have need for it. | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# frozen_string_literal: true | ||
|
||
ActiveRecord::Schema.define do | ||
# Set up any tables you need to exist for your test suite that don't belong | ||
# in migrations. | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
*.log |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.