switchman 3.0.2 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Rakefile +1 -1
- data/db/migrate/20180828183945_add_default_shard_index.rb +1 -1
- data/db/migrate/20180828192111_add_timestamps_to_shards.rb +1 -1
- data/lib/switchman/action_controller/caching.rb +2 -2
- data/lib/switchman/active_record/abstract_adapter.rb +2 -13
- data/lib/switchman/active_record/associations.rb +223 -0
- data/lib/switchman/active_record/attribute_methods.rb +144 -63
- data/lib/switchman/active_record/base.rb +100 -43
- data/lib/switchman/active_record/calculations.rb +12 -5
- data/lib/switchman/active_record/connection_pool.rb +9 -31
- data/lib/switchman/active_record/database_configurations.rb +18 -2
- data/lib/switchman/active_record/finder_methods.rb +2 -2
- data/lib/switchman/active_record/migration.rb +7 -4
- data/lib/switchman/active_record/model_schema.rb +1 -1
- data/lib/switchman/active_record/persistence.rb +7 -2
- data/lib/switchman/active_record/postgresql_adapter.rb +6 -2
- data/lib/switchman/active_record/predicate_builder.rb +1 -1
- data/lib/switchman/active_record/query_methods.rb +27 -14
- data/lib/switchman/active_record/reflection.rb +1 -1
- data/lib/switchman/active_record/relation.rb +25 -24
- data/lib/switchman/active_record/statement_cache.rb +2 -2
- data/lib/switchman/active_record/table_definition.rb +1 -1
- data/lib/switchman/active_record/test_fixtures.rb +43 -0
- data/lib/switchman/active_support/cache.rb +16 -0
- data/lib/switchman/arel.rb +28 -6
- data/lib/switchman/database_server.rb +71 -65
- data/lib/switchman/default_shard.rb +0 -2
- data/lib/switchman/engine.rb +67 -125
- data/lib/switchman/errors.rb +4 -2
- data/lib/switchman/guard_rail/relation.rb +6 -9
- data/lib/switchman/guard_rail.rb +5 -0
- data/lib/switchman/parallel.rb +68 -0
- data/lib/switchman/r_spec_helper.rb +5 -17
- data/lib/switchman/rails.rb +1 -4
- data/{app/models → lib}/switchman/shard.rb +61 -188
- data/lib/switchman/sharded_instrumenter.rb +1 -1
- data/lib/switchman/standard_error.rb +11 -12
- data/{app/models → lib}/switchman/unsharded_record.rb +1 -1
- data/lib/switchman/version.rb +1 -1
- data/lib/switchman.rb +22 -2
- data/lib/tasks/switchman.rake +24 -13
- metadata +24 -22
- data/lib/switchman/active_record/association.rb +0 -206
- data/lib/switchman/open4.rb +0 -80
data/lib/switchman/engine.rb
CHANGED
|
@@ -8,101 +8,27 @@ module Switchman
|
|
|
8
8
|
config.active_record.legacy_connection_handling = false
|
|
9
9
|
config.active_record.writing_role = :primary
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
::GuardRail.singleton_class.prepend(GuardRail::ClassMethods)
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
result[key] = ::ActiveSupport::Cache.lookup_store(value)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
cache_store_config.each do |key, value| # rubocop:disable Style/CombinableLoops
|
|
22
|
-
next unless value.is_a?(String)
|
|
23
|
-
|
|
24
|
-
result[key] = result[value]
|
|
25
|
-
end
|
|
26
|
-
result
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
initializer 'switchman.initialize_cache', before: 'initialize_cache' do
|
|
30
|
-
require 'switchman/active_support/cache'
|
|
31
|
-
::ActiveSupport::Cache.singleton_class.prepend(ActiveSupport::Cache::ClassMethods)
|
|
32
|
-
|
|
33
|
-
# if we haven't already setup our cache map out-of-band, set it up from
|
|
34
|
-
# config.cache_store now. behaves similarly to Rails' default
|
|
35
|
-
# initialize_cache initializer, but for each value in the map, rather
|
|
36
|
-
# than just Rails.cache. if config.cache_store is a flat value, uses it
|
|
37
|
-
# to fill just the Rails.env entry in the cache map.
|
|
38
|
-
unless Switchman.config[:cache_map].present?
|
|
39
|
-
cache_store_config = ::Rails.configuration.cache_store
|
|
40
|
-
cache_store_config = { ::Rails.env => cache_store_config } unless cache_store_config.is_a?(Hash)
|
|
41
|
-
|
|
42
|
-
Switchman.config[:cache_map] = Engine.lookup_stores(cache_store_config)
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
# if the configured cache map (either from before, or as populated from
|
|
46
|
-
# config.cache_store) didn't have an entry for Rails.env, add one using
|
|
47
|
-
# lookup_store(nil); matches the behavior of Rails' default
|
|
48
|
-
# initialize_cache initializer when config.cache_store is nil.
|
|
49
|
-
unless Switchman.config[:cache_map].key?(::Rails.env)
|
|
50
|
-
value = ::ActiveSupport::Cache.lookup_store(nil)
|
|
51
|
-
Switchman.config[:cache_map][::Rails.env] = value
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
middlewares = Switchman.config[:cache_map].values.map do |store|
|
|
55
|
-
store.middleware if store.respond_to?(:middleware)
|
|
56
|
-
end.compact.uniq
|
|
57
|
-
middlewares.each do |middleware|
|
|
58
|
-
config.middleware.insert_before('Rack::Runtime', middleware)
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# prevent :initialize_cache from trying to (or needing to) set
|
|
62
|
-
# Rails.cache. once our switchman.extend_ar initializer (below) runs
|
|
63
|
-
# Rails.cache will be overridden to pull appropriate values from the
|
|
64
|
-
# cache map, but between now and then, Rails.cache should return the
|
|
65
|
-
# Rails.env entry in the cache map.
|
|
66
|
-
::Rails.cache = Switchman.config[:cache_map][::Rails.env]
|
|
13
|
+
# after :initialize_dependency_mechanism to ensure autoloading is configured for any downstream initializers that care
|
|
14
|
+
# In rails 7.0 we should be able to just use an explicit after on configuring the once autoloaders and not need to go monkey around with initializer order
|
|
15
|
+
if ::Rails.version < '7.0'
|
|
16
|
+
initialize_dependency_mechanism = ::Rails::Application::Bootstrap.initializers.find { |i| i.name == :initialize_dependency_mechanism }
|
|
17
|
+
initialize_dependency_mechanism.instance_variable_get(:@options)[:after] = :set_autoload_paths
|
|
67
18
|
end
|
|
68
19
|
|
|
69
|
-
initializer 'switchman.
|
|
20
|
+
initializer 'switchman.active_record_patch',
|
|
21
|
+
before: 'active_record.initialize_database',
|
|
22
|
+
after: (::Rails.version < '7.0' ? :initialize_dependency_mechanism : :setup_once_autoloader) do
|
|
70
23
|
::ActiveSupport.on_load(:active_record) do
|
|
71
|
-
|
|
72
|
-
require '
|
|
73
|
-
require 'switchman/active_record/attribute_methods'
|
|
74
|
-
require 'switchman/active_record/base'
|
|
75
|
-
require 'switchman/active_record/calculations'
|
|
76
|
-
require 'switchman/active_record/connection_pool'
|
|
77
|
-
require 'switchman/active_record/database_configurations'
|
|
78
|
-
require 'switchman/active_record/database_configurations/database_config'
|
|
79
|
-
require 'switchman/active_record/finder_methods'
|
|
80
|
-
require 'switchman/active_record/log_subscriber'
|
|
81
|
-
require 'switchman/active_record/migration'
|
|
82
|
-
require 'switchman/active_record/model_schema'
|
|
83
|
-
require 'switchman/active_record/persistence'
|
|
84
|
-
require 'switchman/active_record/predicate_builder'
|
|
85
|
-
require 'switchman/active_record/query_cache'
|
|
86
|
-
require 'switchman/active_record/query_methods'
|
|
87
|
-
require 'switchman/active_record/reflection'
|
|
88
|
-
require 'switchman/active_record/relation'
|
|
89
|
-
require 'switchman/active_record/spawn_methods'
|
|
90
|
-
require 'switchman/active_record/statement_cache'
|
|
91
|
-
require 'switchman/active_record/tasks/database_tasks'
|
|
92
|
-
require 'switchman/active_record/type_caster'
|
|
93
|
-
require 'switchman/arel'
|
|
94
|
-
require 'switchman/call_super'
|
|
95
|
-
require 'switchman/rails'
|
|
96
|
-
require 'switchman/guard_rail/relation'
|
|
97
|
-
require 'switchman/standard_error'
|
|
98
|
-
|
|
99
|
-
::StandardError.include(StandardError)
|
|
24
|
+
# Switchman requires postgres, so just always load the pg adapter
|
|
25
|
+
require 'active_record/connection_adapters/postgresql_adapter'
|
|
100
26
|
|
|
101
27
|
self.default_shard = ::Rails.env.to_sym
|
|
102
28
|
self.default_role = :primary
|
|
103
29
|
|
|
104
|
-
|
|
105
|
-
|
|
30
|
+
prepend ActiveRecord::Base
|
|
31
|
+
prepend ActiveRecord::AttributeMethods
|
|
106
32
|
include ActiveRecord::Persistence
|
|
107
33
|
singleton_class.prepend ActiveRecord::ModelSchema::ClassMethods
|
|
108
34
|
|
|
@@ -111,22 +37,24 @@ module Switchman
|
|
|
111
37
|
::ActiveRecord::StatementCache::BindMap.prepend(ActiveRecord::StatementCache::BindMap)
|
|
112
38
|
::ActiveRecord::StatementCache::Substitute.send(:attr_accessor, :primary, :sharded)
|
|
113
39
|
|
|
114
|
-
::ActiveRecord::Associations::CollectionAssociation.prepend(ActiveRecord::CollectionAssociation)
|
|
115
|
-
::ActiveRecord::Associations::HasOneAssociation.prepend(ActiveRecord::ForeignAssociation)
|
|
116
|
-
::ActiveRecord::Associations::HasManyAssociation.prepend(ActiveRecord::ForeignAssociation)
|
|
40
|
+
::ActiveRecord::Associations::CollectionAssociation.prepend(ActiveRecord::Associations::CollectionAssociation)
|
|
41
|
+
::ActiveRecord::Associations::HasOneAssociation.prepend(ActiveRecord::Associations::ForeignAssociation)
|
|
42
|
+
::ActiveRecord::Associations::HasManyAssociation.prepend(ActiveRecord::Associations::ForeignAssociation)
|
|
117
43
|
|
|
118
44
|
::ActiveRecord::PredicateBuilder.singleton_class.prepend(ActiveRecord::PredicateBuilder)
|
|
119
45
|
|
|
120
|
-
prepend(ActiveRecord::AutosaveAssociation)
|
|
46
|
+
prepend(ActiveRecord::Associations::AutosaveAssociation)
|
|
121
47
|
|
|
122
|
-
::ActiveRecord::Associations::Association.prepend(ActiveRecord::Association)
|
|
123
|
-
::ActiveRecord::Associations::BelongsToAssociation.prepend(ActiveRecord::BelongsToAssociation)
|
|
124
|
-
::ActiveRecord::Associations::CollectionProxy.include(ActiveRecord::CollectionProxy)
|
|
48
|
+
::ActiveRecord::Associations::Association.prepend(ActiveRecord::Associations::Association)
|
|
49
|
+
::ActiveRecord::Associations::BelongsToAssociation.prepend(ActiveRecord::Associations::BelongsToAssociation)
|
|
50
|
+
::ActiveRecord::Associations::CollectionProxy.include(ActiveRecord::Associations::CollectionProxy)
|
|
125
51
|
|
|
126
|
-
::ActiveRecord::Associations::Preloader::Association.prepend(ActiveRecord::Preloader::Association)
|
|
52
|
+
::ActiveRecord::Associations::Preloader::Association.prepend(ActiveRecord::Associations::Preloader::Association)
|
|
53
|
+
::ActiveRecord::Associations::Preloader::Association::LoaderQuery.prepend(ActiveRecord::Associations::Preloader::Association::LoaderQuery) unless ::Rails.version < '7.0'
|
|
127
54
|
::ActiveRecord::ConnectionAdapters::AbstractAdapter.prepend(ActiveRecord::AbstractAdapter)
|
|
128
55
|
::ActiveRecord::ConnectionAdapters::ConnectionPool.prepend(ActiveRecord::ConnectionPool)
|
|
129
56
|
::ActiveRecord::ConnectionAdapters::AbstractAdapter.prepend(ActiveRecord::QueryCache)
|
|
57
|
+
::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.prepend(ActiveRecord::PostgreSQLAdapter)
|
|
130
58
|
|
|
131
59
|
::ActiveRecord::DatabaseConfigurations.prepend(ActiveRecord::DatabaseConfigurations)
|
|
132
60
|
::ActiveRecord::DatabaseConfigurations::DatabaseConfig.prepend(ActiveRecord::DatabaseConfigurations::DatabaseConfig)
|
|
@@ -150,60 +78,74 @@ module Switchman
|
|
|
150
78
|
::ActiveRecord::Relation.include(CallSuper)
|
|
151
79
|
|
|
152
80
|
::ActiveRecord::PredicateBuilder::AssociationQueryValue.prepend(ActiveRecord::PredicateBuilder::AssociationQueryValue)
|
|
81
|
+
::ActiveRecord::PredicateBuilder::PolymorphicArrayValue.prepend(ActiveRecord::PredicateBuilder::AssociationQueryValue)
|
|
153
82
|
|
|
154
83
|
::ActiveRecord::Tasks::DatabaseTasks.singleton_class.prepend(ActiveRecord::Tasks::DatabaseTasks)
|
|
155
84
|
|
|
85
|
+
::ActiveRecord::TestFixtures.prepend(ActiveRecord::TestFixtures)
|
|
86
|
+
|
|
156
87
|
::ActiveRecord::TypeCaster::Map.include(ActiveRecord::TypeCaster::Map)
|
|
157
88
|
::ActiveRecord::TypeCaster::Connection.include(ActiveRecord::TypeCaster::Connection)
|
|
158
89
|
|
|
159
|
-
::Rails.singleton_class.prepend(Rails::ClassMethods)
|
|
160
|
-
|
|
161
90
|
::Arel::Table.prepend(Arel::Table)
|
|
162
91
|
::Arel::Visitors::ToSql.prepend(Arel::Visitors::ToSql)
|
|
163
|
-
end
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
def self.foreign_key_check(name, type, limit: nil)
|
|
167
|
-
puts "WARNING: All foreign keys need to be 8-byte integers. #{name} looks like a foreign key. If so, please add the option: `:limit => 8`" if name.to_s =~ /_id\z/ && type.to_s == 'integer' && limit.to_i < 8
|
|
168
|
-
end
|
|
169
92
|
|
|
170
|
-
initializer 'switchman.extend_connection_adapters', after: 'active_record.initialize_database' do
|
|
171
|
-
::ActiveSupport.on_load(:active_record) do
|
|
172
93
|
::ActiveRecord::ConnectionAdapters::AbstractAdapter.descendants.each do |klass|
|
|
173
94
|
klass.prepend(ActiveRecord::AbstractAdapter::ForeignKeyCheck)
|
|
174
95
|
end
|
|
175
96
|
|
|
176
|
-
require 'switchman/active_record/table_definition'
|
|
177
97
|
::ActiveRecord::ConnectionAdapters::TableDefinition.prepend(ActiveRecord::TableDefinition)
|
|
178
|
-
|
|
179
|
-
if defined?(::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
|
|
180
|
-
require 'switchman/active_record/postgresql_adapter'
|
|
181
|
-
::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.prepend(ActiveRecord::PostgreSQLAdapter)
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
Shard.send(:initialize_sharding)
|
|
185
98
|
end
|
|
99
|
+
# Ensure that ActiveRecord::Base is always loaded before any app-level initializers can go try to load Switchman::Shard or we get a loop
|
|
100
|
+
::ActiveRecord::Base
|
|
186
101
|
end
|
|
187
102
|
|
|
188
|
-
initializer 'switchman.
|
|
189
|
-
::ActiveSupport.on_load(:
|
|
190
|
-
|
|
191
|
-
require 'active_record/base'
|
|
103
|
+
initializer 'switchman.error_patch', after: 'active_record.initialize_database' do
|
|
104
|
+
::ActiveSupport.on_load(:active_record) do
|
|
105
|
+
::StandardError.include(StandardError)
|
|
192
106
|
end
|
|
193
107
|
end
|
|
194
108
|
|
|
195
|
-
initializer 'switchman.
|
|
196
|
-
::ActiveSupport.
|
|
197
|
-
require 'switchman/guard_rail'
|
|
109
|
+
initializer 'switchman.initialize_cache', before: :initialize_cache, after: 'active_record.initialize_database' do
|
|
110
|
+
::ActiveSupport::Cache.singleton_class.prepend(ActiveSupport::Cache::ClassMethods)
|
|
198
111
|
|
|
199
|
-
|
|
112
|
+
# if we haven't already setup our cache map out-of-band, set it up from
|
|
113
|
+
# config.cache_store now. behaves similarly to Rails' default
|
|
114
|
+
# initialize_cache initializer, but for each value in the map, rather
|
|
115
|
+
# than just Rails.cache. if config.cache_store is a flat value, uses it
|
|
116
|
+
# to fill just the Rails.env entry in the cache map.
|
|
117
|
+
unless Switchman.config[:cache_map].present?
|
|
118
|
+
cache_store_config = ::Rails.configuration.cache_store
|
|
119
|
+
cache_store_config = { ::Rails.env => cache_store_config } unless cache_store_config.is_a?(Hash)
|
|
120
|
+
|
|
121
|
+
Switchman.config[:cache_map] = ::ActiveSupport::Cache.lookup_stores(cache_store_config)
|
|
200
122
|
end
|
|
201
|
-
end
|
|
202
123
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
124
|
+
# if the configured cache map (either from before, or as populated from
|
|
125
|
+
# config.cache_store) didn't have an entry for Rails.env, add one using
|
|
126
|
+
# lookup_store(nil); matches the behavior of Rails' default
|
|
127
|
+
# initialize_cache initializer when config.cache_store is nil.
|
|
128
|
+
unless Switchman.config[:cache_map].key?(::Rails.env)
|
|
129
|
+
value = ::ActiveSupport::Cache.lookup_store(nil)
|
|
130
|
+
Switchman.config[:cache_map][::Rails.env] = value
|
|
131
|
+
end
|
|
206
132
|
|
|
133
|
+
middlewares = Switchman.config[:cache_map].values.map do |store|
|
|
134
|
+
store.middleware if store.respond_to?(:middleware)
|
|
135
|
+
end.compact.uniq
|
|
136
|
+
middlewares.each do |middleware|
|
|
137
|
+
config.middleware.insert_before('Rack::Runtime', middleware)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# prevent :initialize_cache from trying to (or needing to) set
|
|
141
|
+
# Rails.cache. once our switchman.extend_ar initializer (below) runs
|
|
142
|
+
# Rails.cache will be overridden to pull appropriate values from the
|
|
143
|
+
# cache map, but between now and then, Rails.cache should return the
|
|
144
|
+
# Rails.env entry in the cache map.
|
|
145
|
+
::Rails.cache = Switchman.config[:cache_map][::Rails.env]
|
|
146
|
+
::Rails.singleton_class.prepend(Rails::ClassMethods)
|
|
147
|
+
|
|
148
|
+
::ActiveSupport.on_load(:action_controller) do
|
|
207
149
|
::ActionController::Base.include(ActionController::Caching)
|
|
208
150
|
end
|
|
209
151
|
end
|
data/lib/switchman/errors.rb
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Switchman
|
|
4
|
-
|
|
4
|
+
module Errors
|
|
5
|
+
class NonExistentShardError < RuntimeError; end
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
class ParallelShardExecError < RuntimeError; end
|
|
8
|
+
end
|
|
7
9
|
end
|
|
@@ -5,21 +5,18 @@ module Switchman
|
|
|
5
5
|
module Relation
|
|
6
6
|
def exec_queries(*args)
|
|
7
7
|
if lock_value
|
|
8
|
-
db = Shard.current(
|
|
9
|
-
|
|
8
|
+
db = Shard.current(connection_class_for_self).database_server
|
|
9
|
+
db.unguard { super }
|
|
10
|
+
else
|
|
11
|
+
super
|
|
10
12
|
end
|
|
11
|
-
super
|
|
12
13
|
end
|
|
13
14
|
|
|
14
15
|
%w[update_all delete_all].each do |method|
|
|
15
16
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
16
17
|
def #{method}(*args)
|
|
17
|
-
db = Shard.current(
|
|
18
|
-
|
|
19
|
-
db.unguard { super }
|
|
20
|
-
else
|
|
21
|
-
super
|
|
22
|
-
end
|
|
18
|
+
db = Shard.current(connection_class_for_self).database_server
|
|
19
|
+
db.unguard { super }
|
|
23
20
|
end
|
|
24
21
|
RUBY
|
|
25
22
|
end
|
data/lib/switchman/guard_rail.rb
CHANGED
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
module Switchman
|
|
4
4
|
module GuardRail
|
|
5
5
|
module ClassMethods
|
|
6
|
+
def environment
|
|
7
|
+
# no overrides so we get the global role, not the role for the default shard
|
|
8
|
+
::ActiveRecord::Base.current_role(without_overrides: true)
|
|
9
|
+
end
|
|
10
|
+
|
|
6
11
|
def activate(role)
|
|
7
12
|
DatabaseServer.send(:reference_role, role)
|
|
8
13
|
super
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'parallel'
|
|
4
|
+
|
|
5
|
+
module Switchman
|
|
6
|
+
module Parallel
|
|
7
|
+
module UndumpableException
|
|
8
|
+
def initialize(original)
|
|
9
|
+
super
|
|
10
|
+
@active_shards = original.instance_variable_get(:@active_shards)
|
|
11
|
+
current_shard
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class QuietExceptionWrapper
|
|
16
|
+
attr_accessor :name
|
|
17
|
+
|
|
18
|
+
def initialize(name, wrapper)
|
|
19
|
+
@name = name
|
|
20
|
+
@wrapper = wrapper
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def exception
|
|
24
|
+
@wrapper.exception
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
class UndumpableResult
|
|
29
|
+
attr_reader :name
|
|
30
|
+
|
|
31
|
+
def initialize(result)
|
|
32
|
+
@name = result.inspect
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def inspect
|
|
36
|
+
"#<UndumpableResult:#{name}>"
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
class ResultWrapper
|
|
41
|
+
attr_reader :result
|
|
42
|
+
|
|
43
|
+
def initialize(result)
|
|
44
|
+
@result =
|
|
45
|
+
begin
|
|
46
|
+
Marshal.dump(result) && result
|
|
47
|
+
rescue
|
|
48
|
+
UndumpableResult.new(result)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
class PrefixingIO
|
|
54
|
+
delegate_missing_to :@original_io
|
|
55
|
+
|
|
56
|
+
def initialize(prefix, original_io)
|
|
57
|
+
@prefix = prefix
|
|
58
|
+
@original_io = original_io
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def puts(*args)
|
|
62
|
+
args.flatten.each { |arg| @original_io.puts "#{@prefix}: #{arg}" }
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
::Parallel::UndumpableException.prepend(::Switchman::Parallel::UndumpableException)
|
|
@@ -70,7 +70,10 @@ module Switchman
|
|
|
70
70
|
Shard.default(reload: true)
|
|
71
71
|
puts 'Done!'
|
|
72
72
|
|
|
73
|
+
main_pid = Process.pid
|
|
73
74
|
at_exit do
|
|
75
|
+
next unless main_pid == Process.pid
|
|
76
|
+
|
|
74
77
|
# preserve rspec's exit status
|
|
75
78
|
status = $!.is_a?(::SystemExit) ? $!.status : nil
|
|
76
79
|
puts 'Tearing down sharding for all specs'
|
|
@@ -111,28 +114,12 @@ module Switchman
|
|
|
111
114
|
Shard.default(reload: true)
|
|
112
115
|
@shard1 = Shard.find(@shard1.id)
|
|
113
116
|
@shard2 = Shard.find(@shard2.id)
|
|
114
|
-
shards = [@shard2]
|
|
115
|
-
shards << @shard1 unless @shard1.database_server == Shard.default.database_server
|
|
116
|
-
shards.each do |shard|
|
|
117
|
-
shard.activate do
|
|
118
|
-
::ActiveRecord::Base.connection.begin_transaction joinable: false
|
|
119
|
-
end
|
|
120
|
-
end
|
|
121
117
|
end
|
|
122
118
|
end
|
|
123
119
|
|
|
124
120
|
klass.after do
|
|
125
121
|
next if @@sharding_failed
|
|
126
122
|
|
|
127
|
-
if use_transactional_tests
|
|
128
|
-
shards = [@shard2]
|
|
129
|
-
shards << @shard1 unless @shard1.database_server == Shard.default.database_server
|
|
130
|
-
shards.each do |shard|
|
|
131
|
-
shard.activate do
|
|
132
|
-
::ActiveRecord::Base.connection.rollback_transaction if ::ActiveRecord::Base.connection.transaction_open?
|
|
133
|
-
end
|
|
134
|
-
end
|
|
135
|
-
end
|
|
136
123
|
# clean up after specs
|
|
137
124
|
DatabaseServer.all.each do |ds|
|
|
138
125
|
if ds.fake? && ds != @shard2.database_server
|
|
@@ -143,7 +130,8 @@ module Switchman
|
|
|
143
130
|
end
|
|
144
131
|
|
|
145
132
|
klass.after(:all) do
|
|
146
|
-
|
|
133
|
+
# Don't truncate because that can create some fun cross-connection lock contention
|
|
134
|
+
Shard.delete_all
|
|
147
135
|
Switchman.cache.delete('default_shard')
|
|
148
136
|
Shard.default(reload: true)
|
|
149
137
|
end
|
data/lib/switchman/rails.rb
CHANGED
|
@@ -4,10 +4,7 @@ module Switchman
|
|
|
4
4
|
module Rails
|
|
5
5
|
module ClassMethods
|
|
6
6
|
def self.prepended(klass)
|
|
7
|
-
#
|
|
8
|
-
# Rails.cache(_without_sharding) to the value from the config file. but now
|
|
9
|
-
# that that's done (the bootstrap happened before this module is included
|
|
10
|
-
# into Rails), we want to make sure no one tries to assign to Rails.cache,
|
|
7
|
+
# we want to make sure no one tries to assign to Rails.cache,
|
|
11
8
|
# because it would be wrong w.r.t. sharding.
|
|
12
9
|
klass.send(:remove_method, :cache=)
|
|
13
10
|
end
|