Module: ActiveRecordSlave

Defined in:
lib/active_record_slave/active_record_slave.rb,
lib/active_record_slave/slave.rb,
lib/active_record_slave/errors.rb,
lib/active_record_slave/railtie.rb,
lib/active_record_slave/version.rb,
lib/active_record_slave/extensions.rb

Overview

ActiveRecord read from a slave

Defined Under Namespace

Modules: Extensions Classes: Railtie, Slave, TransactionAttempted

Constant Summary collapse

VERSION =
'1.6.0'
SELECT_METHODS =

Select Methods

[:select, :select_all, :select_one, :select_rows, :select_value, :select_values]

Class Method Summary collapse

Class Method Details

.block_transactionsObject

When only reading from a slave it is important to prevent entering any into a transaction since the transaction still sends traffic to the master that will cause the master database to slow down processing empty transactions.



73
74
75
76
77
78
79
80
81
# File 'lib/active_record_slave/active_record_slave.rb', line 73

def self.block_transactions
  begin
    previous = Thread.current.thread_variable_get(:active_record_slave_transaction)
    Thread.current.thread_variable_set(:active_record_slave_transaction, :block)
    yield
  ensure
    Thread.current.thread_variable_set(:active_record_slave_transaction, previous)
  end
end

.block_transactions?Boolean

Whether any attempt to start a transaction should result in an exception

Returns:

  • (Boolean)


117
118
119
# File 'lib/active_record_slave/active_record_slave.rb', line 117

def self.block_transactions?
  Thread.current.thread_variable_get(:active_record_slave_transaction) == :block
end

.ignore_transactions=(ignore_transactions) ⇒ Object

Set whether slave reads should ignore transactions



132
133
134
# File 'lib/active_record_slave/active_record_slave.rb', line 132

def self.ignore_transactions=(ignore_transactions)
  @ignore_transactions = ignore_transactions
end

.ignore_transactions?Boolean

Returns whether slave reads are ignoring transactions

Returns:

  • (Boolean)


127
128
129
# File 'lib/active_record_slave/active_record_slave.rb', line 127

def self.ignore_transactions?
  @ignore_transactions
end

.install!(adapter_class = nil, environment = nil) ⇒ Object

Install ActiveRecord::Slave into ActiveRecord to redirect reads to the slave Parameters:

adapter_class:
  By default, only the default Database adapter (ActiveRecord::Base.connection.class)
  is extended with slave read capabilities

environment:
  In a non-Rails environment, supply the environment such as
  'development', 'production'


21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/active_record_slave/active_record_slave.rb', line 21

def self.install!(adapter_class = nil, environment = nil)
  slave_config =
    if ActiveRecord::Base.connection.respond_to?(:config)
      ActiveRecord::Base.connection.config[:slave]
    else
      ActiveRecord::Base.configurations[environment || Rails.env]['slave']
    end
  if slave_config
    ActiveRecord::Base.logger.info "ActiveRecordSlave.install! v#{ActiveRecordSlave::VERSION} Establishing connection to slave database"
    Slave.establish_connection(slave_config)

    # Inject a new #select method into the ActiveRecord Database adapter
    base = adapter_class || ActiveRecord::Base.connection.class
    base.include(Extensions)
  else
    ActiveRecord::Base.logger.info "ActiveRecordSlave not installed since no slave database defined"
  end
end

.read_from_masterObject

Force reads for the supplied block to read from the master database Only applies to calls made within the current thread



42
43
44
45
46
47
48
49
50
51
# File 'lib/active_record_slave/active_record_slave.rb', line 42

def self.read_from_master
  return yield if read_from_master?
  begin
    previous = Thread.current.thread_variable_get(:active_record_slave)
    read_from_master!
    yield
  ensure
    Thread.current.thread_variable_set(:active_record_slave, previous)
  end
end

.read_from_master!Object

Force all subsequent reads on this thread and any fibers called by this thread to go the master



107
108
109
# File 'lib/active_record_slave/active_record_slave.rb', line 107

def self.read_from_master!
  Thread.current.thread_variable_set(:active_record_slave, :master)
end

.read_from_master?Boolean

Whether this thread is currently forcing all reads to go against the master database

Returns:

  • (Boolean)


97
98
99
# File 'lib/active_record_slave/active_record_slave.rb', line 97

def self.read_from_master?
  Thread.current.thread_variable_get(:active_record_slave) == :master
end

.read_from_slaveObject

The default behavior can also set to read/write operations against master Create an initializer file config/initializer/active_record_slave.rb and set ActiveRecordSlave.read_from_master! to force read from master. Then use this method and supply block to read from the slave database Only applies to calls made within the current thread



59
60
61
62
63
64
65
66
67
68
# File 'lib/active_record_slave/active_record_slave.rb', line 59

def self.read_from_slave
  return yield if read_from_slave?
  begin
    previous = Thread.current.thread_variable_get(:active_record_slave)
    read_from_slave!
    yield
  ensure
    Thread.current.thread_variable_set(:active_record_slave, previous)
  end
end

.read_from_slave!Object

Subsequent reads on this thread and any fibers called by this thread can go to a slave



112
113
114
# File 'lib/active_record_slave/active_record_slave.rb', line 112

def self.read_from_slave!
  Thread.current.thread_variable_set(:active_record_slave, nil)
end

.read_from_slave?Boolean

Whether this thread is currently forcing all reads to go against the slave database

Returns:

  • (Boolean)


102
103
104
# File 'lib/active_record_slave/active_record_slave.rb', line 102

def self.read_from_slave?
  Thread.current.thread_variable_get(:active_record_slave).nil?
end

.skip_transactionsObject

During this block any attempts to start or end transactions will be ignored. This extreme action should only be taken when 100% certain no writes are going to be performed.



86
87
88
89
90
91
92
93
94
# File 'lib/active_record_slave/active_record_slave.rb', line 86

def self.skip_transactions
  begin
    previous = Thread.current.thread_variable_get(:active_record_slave_transaction)
    Thread.current.thread_variable_set(:active_record_slave_transaction, :skip)
    yield
  ensure
    Thread.current.thread_variable_set(:active_record_slave_transaction, previous)
  end
end

.skip_transactions?Boolean

Whether any attempt to start a transaction should be skipped.

Returns:

  • (Boolean)


122
123
124
# File 'lib/active_record_slave/active_record_slave.rb', line 122

def self.skip_transactions?
  Thread.current.thread_variable_get(:active_record_slave_transaction) == :skip
end