Skip to content

Commit

Permalink
Merge pull request thiagopradi#461 from thiagopradi/fixing_replicatio…
Browse files Browse the repository at this point in the history
…n_bug_new

[WIP] Fixing Replication Bug
  • Loading branch information
thiagopradi authored Nov 4, 2017
2 parents 3ed0f33 + e943c43 commit 705cf8f
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 3 deletions.
9 changes: 9 additions & 0 deletions lib/octopus.rb
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ def self.rails4?
ActiveRecord::VERSION::MAJOR == 4
end

def self.rails40?
rails4? && ActiveRecord::VERSION::MINOR == 0
end

def self.rails41_only?
rails4? && ActiveRecord::VERSION::MINOR == 1
end

def self.rails41?
rails4? && ActiveRecord::VERSION::MINOR >= 1
end
Expand Down Expand Up @@ -175,6 +183,7 @@ def self.fully_replicated(&_block)
require 'octopus/shard_tracking/dynamic'

require 'octopus/model'
require 'octopus/result_patch'
require 'octopus/migration'
require 'octopus/association'
require 'octopus/collection_association'
Expand Down
22 changes: 21 additions & 1 deletion lib/octopus/model.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,25 @@ def set_current_shard
self.current_shard = shard if self.class.allowed_shard?(shard)
end

def init_with(coder)
current_shard_value = if Octopus.rails40? || Octopus.rails41_only?
coder['attributes']['current_shard'] if coder['attributes']['current_shard'].present?
else
coder['attributes']['current_shard'].value if coder['attributes']['current_shard'].present? && coder['attributes']['current_shard'].value.present?
end

if Octopus.rails40? || Octopus.rails41_only?
coder['attributes'].delete('current_shard')
else
coder['attributes'].send(:attributes).send(:values).delete('current_shard')
coder['attributes'].send(:attributes).send(:delegate_hash).delete('current_shard')
end

obj = super
obj.current_shard = current_shard_value if current_shard_value.present?
obj
end

def should_set_current_shard?
self.respond_to?(:current_shard) && !current_shard.nil?
end
Expand Down Expand Up @@ -86,9 +105,10 @@ def allow_shard(*shards)
end

def hijack_methods
around_save :run_on_shard, :unless => lambda { self.class.custom_octopus_connection }
after_initialize :set_current_shard

around_save :run_on_shard, :unless => lambda { self.class.custom_octopus_connection }

class_attribute :custom_octopus_connection

class << self
Expand Down
14 changes: 12 additions & 2 deletions lib/octopus/proxy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,13 @@ def legacy_method_missing_logic(method, *args, &block)
elsif should_send_queries_to_replicated_databases?(method)
send_queries_to_selected_slave(method, *args, &block)
else
select_connection.send(method, *args, &block)
val = select_connection.send(method, *args, &block)

if val.instance_of? ActiveRecord::Result
val.current_shard = shard_name
end

val
end
end

Expand Down Expand Up @@ -282,7 +288,11 @@ def send_queries_to_balancer(balancer, method, *args, &block)
# while preserving `current_shard`
def send_queries_to_slave(slave, method, *args, &block)
using_shard(slave) do
select_connection.send(method, *args, &block)
val = select_connection.send(method, *args, &block)
if val.instance_of? ActiveRecord::Result
val.current_shard = slave
end
val
end
end

Expand Down
19 changes: 19 additions & 0 deletions lib/octopus/result_patch.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module Octopus::ResultPatch
attr_accessor :current_shard

private

def hash_rows
if current_shard.blank?
super
else
foo = super
foo.each { |f| f.merge!('current_shard' => current_shard) }
foo
end
end
end

class ActiveRecord::Result
prepend Octopus::ResultPatch
end
4 changes: 4 additions & 0 deletions lib/octopus/scope_proxy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ def method_missing(method, *args, &block)
return self
end

if result.respond_to?(:current_shard)
result.current_shard = current_shard
end

result
end

Expand Down
12 changes: 12 additions & 0 deletions spec/config/shards.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,18 @@ production_replicated:
<<: *mysql


production_fully_replicated:
replicated: true
fully_replicated: true

shards:
slave1:
database: octopus_shard_2
<<: *mysql
slave2:
database: octopus_shard_3
<<: *mysql

replicated_with_one_slave:
replicated: true
shards:
Expand Down
11 changes: 11 additions & 0 deletions spec/octopus/model_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -717,5 +717,16 @@
expect(Cat.replicated).to be true
end
end

it "should work on a fully replicated environment" do
OctopusHelper.using_environment :production_fully_replicated do
User.using(:slave1).create!(name: 'Thiago')
User.using(:slave2).create!(name: 'Thiago')

replicated_cat = User.find_by_name 'Thiago'

expect(replicated_cat.current_shard.to_s).to match(/slave/)
end
end
end
end

0 comments on commit 705cf8f

Please sign in to comment.