Hello, 
We use sequel models extensively, including single table inheritance for 
implementing different class behaviors, while sharing tables, all to 
implement a server and service management and orchestration platform. 

We also use a ruby pry console to interact with our app and trigger actions 
in production. In an effort to avoid fat fingers and other errors from 
accidentally killing our fleet, we implemented a default read only console, 
which initially connects to our read replica, and on demand, allows an 
operator to change to a writeable console. This runtime action disconnects 
DB and reconnects to our writable leader, while preserving already loaded 
Sequel::Model objects in memory. Our current method of doing this reassigns 
db for all loaded Sequel::Model.descendants, so that already loaded Sequel 
objects may be preserved and be able to write to the proper db, after 
making the console writable.

Now we are looking to move to Sequel 5, where it seems that setting a 
Model.db= is not possible. We attempted to move to using Model.dataset= to 
achieve the same effect, but then found STI classes lost their custom 
dataset definitions. Also, this is documented as: `You shouldn't call 
set_dataset in the model after applying this plugin, otherwise subclasses 
might use the wrong dataset.` in the docs.

Is it possible to somehow use Sequel's sharding support to implement this 
read only console pattern, or is there a simpler solution that I am 
overlooking?

Looking at the add_servers and remove_servers functions, it does not seem 
clear that we could use them to reassign the backing db of an already 
instantiated sequel model in a pry, which I think is our central use case. 

Our reload code is excerpted below:

def reload!(fast: true)
  failed_files = {}
  with_silenced_logging do
    with_silence_warnings do
      DB.disconnect unless fast
      load 'config/config.rb'
      load 'config/initializers/database.rb'
      Sequel::Model.db = DB unless fast

      Sequel::Model.descendants.each { |m| m.db = DB } unless fast

      $".grep(/\/lib\/(app|web)/e).each do |file|
        maybe_load_file(file) do |failure_reason,exception|
          failed_files[file] = [failure_reason, exception]
        end
      end
    end
  end
end

def writeable_app!
  Shogun::AWS::AwsClient.set_credentials(Config.aws_access_key_id, 
Config.aws_secret_access_key)
  ENV['CONNECT_TO_FOLLOWER'] = 'false'
  reload!(fast: false)
end

def read_only_app!
  Shogun::AWS::AwsClient.set_credentials(Config.readonly_aws_access_key_id, 
Config.readonly_aws_secret_access_key)
  ENV['CONNECT_TO_FOLLOWER'] = 'true'
  reload!(fast: false)
end

And config/initializers/database.rb is :

database_url = if Config.connect_to_follower
                 Config.follower_database_url
               else
                 Config.database_url
               end
DB = Sequel.connect(database_url,
  preconnect: Config.behind_pgbouncer,
  max_connections: Config.sidekiq_concurrency,
  after_connect: proc do |c|
    c.execute("SET application_name TO '#{Config.dyno}'")
    if Config.web_statement_timeout && Config.dyno =~ /^web/i
      c.execute("SET statement_timeout=#{Config.web_statement_timeout};")
    end
  end)
DB.extens

Thanks,
Greg

-- 
You received this message because you are subscribed to the Google Groups 
"sequel-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/sequel-talk.
For more options, visit https://groups.google.com/d/optout.

Reply via email to