switchman 3.0.14 → 3.5.20

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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +16 -15
  3. data/db/migrate/20180828183945_add_default_shard_index.rb +1 -1
  4. data/db/migrate/20190114212900_add_unique_name_indexes.rb +10 -4
  5. data/lib/switchman/action_controller/caching.rb +2 -2
  6. data/lib/switchman/active_record/abstract_adapter.rb +6 -6
  7. data/lib/switchman/active_record/associations.rb +365 -0
  8. data/lib/switchman/active_record/attribute_methods.rb +188 -99
  9. data/lib/switchman/active_record/base.rb +185 -40
  10. data/lib/switchman/active_record/calculations.rb +64 -40
  11. data/lib/switchman/active_record/connection_handler.rb +18 -0
  12. data/lib/switchman/active_record/connection_pool.rb +24 -5
  13. data/lib/switchman/active_record/database_configurations.rb +37 -13
  14. data/lib/switchman/active_record/finder_methods.rb +46 -16
  15. data/lib/switchman/active_record/log_subscriber.rb +11 -5
  16. data/lib/switchman/active_record/migration.rb +52 -8
  17. data/lib/switchman/active_record/model_schema.rb +1 -1
  18. data/lib/switchman/active_record/persistence.rb +31 -3
  19. data/lib/switchman/active_record/postgresql_adapter.rb +11 -10
  20. data/lib/switchman/active_record/predicate_builder.rb +2 -2
  21. data/lib/switchman/active_record/query_cache.rb +49 -20
  22. data/lib/switchman/active_record/query_methods.rb +187 -136
  23. data/lib/switchman/active_record/reflection.rb +1 -1
  24. data/lib/switchman/active_record/relation.rb +33 -26
  25. data/lib/switchman/active_record/spawn_methods.rb +2 -2
  26. data/lib/switchman/active_record/statement_cache.rb +11 -7
  27. data/lib/switchman/active_record/table_definition.rb +1 -1
  28. data/lib/switchman/active_record/tasks/database_tasks.rb +6 -1
  29. data/lib/switchman/active_record/test_fixtures.rb +26 -16
  30. data/lib/switchman/active_support/cache.rb +20 -1
  31. data/lib/switchman/arel.rb +34 -18
  32. data/lib/switchman/call_super.rb +8 -2
  33. data/lib/switchman/database_server.rb +91 -45
  34. data/lib/switchman/default_shard.rb +14 -5
  35. data/lib/switchman/engine.rb +79 -126
  36. data/lib/switchman/environment.rb +2 -2
  37. data/lib/switchman/errors.rb +17 -2
  38. data/lib/switchman/guard_rail/relation.rb +8 -10
  39. data/lib/switchman/guard_rail.rb +5 -0
  40. data/lib/switchman/parallel.rb +68 -0
  41. data/lib/switchman/r_spec_helper.rb +14 -11
  42. data/lib/switchman/rails.rb +2 -5
  43. data/{app/models → lib}/switchman/shard.rb +186 -189
  44. data/lib/switchman/sharded_instrumenter.rb +5 -1
  45. data/lib/switchman/shared_schema_cache.rb +11 -0
  46. data/lib/switchman/standard_error.rb +6 -5
  47. data/lib/switchman/test_helper.rb +2 -2
  48. data/{app/models → lib}/switchman/unsharded_record.rb +1 -1
  49. data/lib/switchman/version.rb +1 -1
  50. data/lib/switchman.rb +44 -12
  51. data/lib/tasks/switchman.rake +74 -53
  52. metadata +42 -53
  53. data/lib/switchman/active_record/association.rb +0 -206
  54. data/lib/switchman/open4.rb +0 -80
@@ -5,109 +5,34 @@ module Switchman
5
5
  isolate_namespace Switchman
6
6
 
7
7
  # enable Rails 6.1 style connection handling
8
- config.active_record.legacy_connection_handling = false
8
+ config.active_record.legacy_connection_handling = false if ::Rails.version < "7.1"
9
9
  config.active_record.writing_role = :primary
10
10
 
11
- config.autoload_once_paths << File.expand_path('app/models', config.paths.path)
11
+ ::GuardRail.singleton_class.prepend(GuardRail::ClassMethods)
12
12
 
13
- def self.lookup_stores(cache_store_config)
14
- result = {}
15
- cache_store_config.each do |key, value|
16
- next if value.is_a?(String)
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
13
+ # after :initialize_dependency_mechanism to ensure autoloading is
14
+ # configured for any downstream initializers that care. In rails 7.0 we
15
+ # should be able to just use an explicit after on configuring the once
16
+ # autoloaders and not need to go monkey around with initializer order
17
+ if ::Rails.version < "7.0"
18
+ initialize_dependency_mechanism = ::Rails::Application::Bootstrap.initializers.find do |i|
19
+ i.name == :initialize_dependency_mechanism
52
20
  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]
21
+ initialize_dependency_mechanism.instance_variable_get(:@options)[:after] = :set_autoload_paths
67
22
  end
68
23
 
69
- initializer 'switchman.extend_ar', before: 'active_record.initialize_database' do
24
+ initializer "switchman.active_record_patch",
25
+ before: "active_record.initialize_database",
26
+ after: ((::Rails.version < "7.0") ? :initialize_dependency_mechanism : :setup_once_autoloader) do
70
27
  ::ActiveSupport.on_load(:active_record) do
71
28
  # Switchman requires postgres, so just always load the pg adapter
72
- require 'active_record/connection_adapters/postgresql_adapter'
73
-
74
- require 'switchman/active_record/abstract_adapter'
75
- require 'switchman/active_record/association'
76
- require 'switchman/active_record/attribute_methods'
77
- require 'switchman/active_record/base'
78
- require 'switchman/active_record/calculations'
79
- require 'switchman/active_record/connection_pool'
80
- require 'switchman/active_record/database_configurations'
81
- require 'switchman/active_record/database_configurations/database_config'
82
- require 'switchman/active_record/finder_methods'
83
- require 'switchman/active_record/log_subscriber'
84
- require 'switchman/active_record/migration'
85
- require 'switchman/active_record/model_schema'
86
- require 'switchman/active_record/persistence'
87
- require 'switchman/active_record/postgresql_adapter'
88
- require 'switchman/active_record/predicate_builder'
89
- require 'switchman/active_record/query_cache'
90
- require 'switchman/active_record/query_methods'
91
- require 'switchman/active_record/reflection'
92
- require 'switchman/active_record/relation'
93
- require 'switchman/active_record/spawn_methods'
94
- require 'switchman/active_record/statement_cache'
95
- require 'switchman/active_record/tasks/database_tasks'
96
- require 'switchman/active_record/type_caster'
97
- require 'switchman/active_record/test_fixtures'
98
- require 'switchman/arel'
99
- require 'switchman/call_super'
100
- require 'switchman/rails'
101
- require 'switchman/guard_rail/relation'
102
- require 'switchman/standard_error'
103
-
104
- ::StandardError.include(StandardError)
29
+ require "active_record/connection_adapters/postgresql_adapter"
105
30
 
106
31
  self.default_shard = ::Rails.env.to_sym
107
32
  self.default_role = :primary
108
33
 
109
34
  prepend ActiveRecord::Base
110
- include ActiveRecord::AttributeMethods
35
+ prepend ActiveRecord::AttributeMethods
111
36
  include ActiveRecord::Persistence
112
37
  singleton_class.prepend ActiveRecord::ModelSchema::ClassMethods
113
38
 
@@ -116,26 +41,36 @@ module Switchman
116
41
  ::ActiveRecord::StatementCache::BindMap.prepend(ActiveRecord::StatementCache::BindMap)
117
42
  ::ActiveRecord::StatementCache::Substitute.send(:attr_accessor, :primary, :sharded)
118
43
 
119
- ::ActiveRecord::Associations::CollectionAssociation.prepend(ActiveRecord::CollectionAssociation)
120
- ::ActiveRecord::Associations::HasOneAssociation.prepend(ActiveRecord::ForeignAssociation)
121
- ::ActiveRecord::Associations::HasManyAssociation.prepend(ActiveRecord::ForeignAssociation)
44
+ ::ActiveRecord::Associations::CollectionAssociation.prepend(ActiveRecord::Associations::CollectionAssociation)
45
+ ::ActiveRecord::Associations::HasOneAssociation.prepend(ActiveRecord::Associations::ForeignAssociation)
46
+ ::ActiveRecord::Associations::HasManyAssociation.prepend(ActiveRecord::Associations::ForeignAssociation)
122
47
 
123
48
  ::ActiveRecord::PredicateBuilder.singleton_class.prepend(ActiveRecord::PredicateBuilder)
124
49
 
125
- prepend(ActiveRecord::AutosaveAssociation)
50
+ prepend(ActiveRecord::Associations::AutosaveAssociation)
126
51
 
127
- ::ActiveRecord::Associations::Association.prepend(ActiveRecord::Association)
128
- ::ActiveRecord::Associations::BelongsToAssociation.prepend(ActiveRecord::BelongsToAssociation)
129
- ::ActiveRecord::Associations::CollectionProxy.include(ActiveRecord::CollectionProxy)
52
+ ::ActiveRecord::Associations::Association.prepend(ActiveRecord::Associations::Association)
53
+ ::ActiveRecord::Associations::BelongsToAssociation.prepend(ActiveRecord::Associations::BelongsToAssociation)
54
+ ::ActiveRecord::Associations::CollectionProxy.include(ActiveRecord::Associations::CollectionProxy)
130
55
 
131
- ::ActiveRecord::Associations::Preloader::Association.prepend(ActiveRecord::Preloader::Association)
56
+ ::ActiveRecord::Associations::Preloader::Association.prepend(ActiveRecord::Associations::Preloader::Association)
57
+ unless ::Rails.version < "7.0"
58
+ ::ActiveRecord::Associations::Preloader::Association::LoaderRecords.prepend(
59
+ ActiveRecord::Associations::Preloader::Association::LoaderRecords
60
+ )
61
+ end
132
62
  ::ActiveRecord::ConnectionAdapters::AbstractAdapter.prepend(ActiveRecord::AbstractAdapter)
63
+ unless ::Rails.version < "7.1"
64
+ ::ActiveRecord::ConnectionAdapters::ConnectionHandler.prepend(ActiveRecord::ConnectionHandler)
65
+ end
133
66
  ::ActiveRecord::ConnectionAdapters::ConnectionPool.prepend(ActiveRecord::ConnectionPool)
134
67
  ::ActiveRecord::ConnectionAdapters::AbstractAdapter.prepend(ActiveRecord::QueryCache)
135
68
  ::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.prepend(ActiveRecord::PostgreSQLAdapter)
136
69
 
137
70
  ::ActiveRecord::DatabaseConfigurations.prepend(ActiveRecord::DatabaseConfigurations)
138
- ::ActiveRecord::DatabaseConfigurations::DatabaseConfig.prepend(ActiveRecord::DatabaseConfigurations::DatabaseConfig)
71
+ ::ActiveRecord::DatabaseConfigurations::DatabaseConfig.prepend(
72
+ ActiveRecord::DatabaseConfigurations::DatabaseConfig
73
+ )
139
74
 
140
75
  ::ActiveRecord::LogSubscriber.prepend(ActiveRecord::LogSubscriber)
141
76
  ::ActiveRecord::Migration.prepend(ActiveRecord::Migration)
@@ -155,8 +90,9 @@ module Switchman
155
90
  ::ActiveRecord::Relation.include(ActiveRecord::SpawnMethods)
156
91
  ::ActiveRecord::Relation.include(CallSuper)
157
92
 
158
- ::ActiveRecord::PredicateBuilder::AssociationQueryValue.prepend(ActiveRecord::PredicateBuilder::AssociationQueryValue)
159
- ::ActiveRecord::PredicateBuilder::PolymorphicArrayValue.prepend(ActiveRecord::PredicateBuilder::AssociationQueryValue)
93
+ ::ActiveRecord::PredicateBuilder::PolymorphicArrayValue.prepend(
94
+ ActiveRecord::PredicateBuilder::PolymorphicArrayValue
95
+ )
160
96
 
161
97
  ::ActiveRecord::Tasks::DatabaseTasks.singleton_class.prepend(ActiveRecord::Tasks::DatabaseTasks)
162
98
 
@@ -165,49 +101,66 @@ module Switchman
165
101
  ::ActiveRecord::TypeCaster::Map.include(ActiveRecord::TypeCaster::Map)
166
102
  ::ActiveRecord::TypeCaster::Connection.include(ActiveRecord::TypeCaster::Connection)
167
103
 
168
- ::Rails.singleton_class.prepend(Rails::ClassMethods)
169
-
170
104
  ::Arel::Table.prepend(Arel::Table)
171
105
  ::Arel::Visitors::ToSql.prepend(Arel::Visitors::ToSql)
172
- end
173
- end
174
106
 
175
- def self.foreign_key_check(name, type, limit: nil)
176
- 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
177
- end
178
-
179
- initializer 'switchman.extend_connection_adapters', after: 'active_record.initialize_database' do
180
- ::ActiveSupport.on_load(:active_record) do
181
107
  ::ActiveRecord::ConnectionAdapters::AbstractAdapter.descendants.each do |klass|
182
108
  klass.prepend(ActiveRecord::AbstractAdapter::ForeignKeyCheck)
183
109
  end
184
110
 
185
- require 'switchman/active_record/table_definition'
186
111
  ::ActiveRecord::ConnectionAdapters::TableDefinition.prepend(ActiveRecord::TableDefinition)
187
-
188
- Shard.send(:initialize_sharding)
189
112
  end
113
+ # Ensure that ActiveRecord::Base is always loaded before any app-level
114
+ # initializers can go try to load Switchman::Shard or we get a loop
115
+ ::ActiveRecord::Base
190
116
  end
191
117
 
192
- initializer 'switchman.eager_load' do
193
- ::ActiveSupport.on_load(:before_eager_load) do
194
- # This needs to be loaded before Switchman::Shard, otherwise it won't autoload it correctly
195
- require 'active_record/base'
118
+ initializer "switchman.error_patch", after: "active_record.initialize_database" do
119
+ ::ActiveSupport.on_load(:active_record) do
120
+ ::StandardError.include(StandardError)
196
121
  end
197
122
  end
198
123
 
199
- initializer 'switchman.extend_guard_rail', before: 'switchman.extend_ar' do
200
- ::ActiveSupport.on_load(:active_record) do
201
- require 'switchman/guard_rail'
124
+ initializer "switchman.initialize_cache", before: :initialize_cache, after: "active_record.initialize_database" do
125
+ ::ActiveSupport::Cache.singleton_class.prepend(ActiveSupport::Cache::ClassMethods)
202
126
 
203
- ::GuardRail.singleton_class.prepend(GuardRail::ClassMethods)
127
+ # if we haven't already setup our cache map out-of-band, set it up from
128
+ # config.cache_store now. behaves similarly to Rails' default
129
+ # initialize_cache initializer, but for each value in the map, rather
130
+ # than just Rails.cache. if config.cache_store is a flat value, uses it
131
+ # to fill just the Rails.env entry in the cache map.
132
+ unless Switchman.config[:cache_map].present?
133
+ cache_store_config = ::Rails.configuration.cache_store
134
+ cache_store_config = { ::Rails.env => cache_store_config } unless cache_store_config.is_a?(Hash)
135
+
136
+ Switchman.config[:cache_map] = ::ActiveSupport::Cache.lookup_stores(cache_store_config)
204
137
  end
205
- end
206
138
 
207
- initializer 'switchman.extend_controller', after: 'guard_rail.extend_ar' do
208
- ::ActiveSupport.on_load(:action_controller) do
209
- require 'switchman/action_controller/caching'
139
+ # if the configured cache map (either from before, or as populated from
140
+ # config.cache_store) didn't have an entry for Rails.env, add one using
141
+ # lookup_store(nil); matches the behavior of Rails' default
142
+ # initialize_cache initializer when config.cache_store is nil.
143
+ unless Switchman.config[:cache_map].key?(::Rails.env)
144
+ value = ::ActiveSupport::Cache.lookup_store(nil)
145
+ Switchman.config[:cache_map][::Rails.env] = value
146
+ end
210
147
 
148
+ middlewares = Switchman.config[:cache_map].values.filter_map do |store|
149
+ store.middleware if store.respond_to?(:middleware)
150
+ end.uniq
151
+ middlewares.each do |middleware|
152
+ config.middleware.insert_before("Rack::Runtime", middleware)
153
+ end
154
+
155
+ # prevent :initialize_cache from trying to (or needing to) set
156
+ # Rails.cache. once our switchman.extend_ar initializer (below) runs
157
+ # Rails.cache will be overridden to pull appropriate values from the
158
+ # cache map, but between now and then, Rails.cache should return the
159
+ # Rails.env entry in the cache map.
160
+ ::Rails.cache = Switchman.config[:cache_map][::Rails.env]
161
+ ::Rails.singleton_class.prepend(Rails::ClassMethods)
162
+
163
+ ::ActiveSupport.on_load(:action_controller) do
211
164
  ::ActionController::Base.include(ActionController::Caching)
212
165
  end
213
166
  end
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'etc'
3
+ require "etc"
4
4
 
5
5
  module Switchman
6
6
  class Environment
7
- def self.cpu_count(nproc_bin = 'nproc')
7
+ def self.cpu_count(nproc_bin = "nproc")
8
8
  return Etc.nprocessors if Etc.respond_to?(:nprocessors)
9
9
 
10
10
  `#{nproc_bin}`.to_i
@@ -1,7 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Switchman
4
- class NonExistentShardError < RuntimeError; end
4
+ module Errors
5
+ class ManuallyCreatedShadowRecordError < RuntimeError
6
+ DEFAULT_MSG = "It looks like you're trying to manually create a shadow record. " \
7
+ "Please use Switchman::ActiveRecord::Base#save_shadow_record instead."
5
8
 
6
- class ParallelShardExecError < RuntimeError; end
9
+ def initialize(msg = DEFAULT_MSG)
10
+ super
11
+ end
12
+ end
13
+
14
+ class NonExistentShardError < RuntimeError; end
15
+
16
+ class ParallelShardExecError < RuntimeError; end
17
+
18
+ class ShadowRecordError < RuntimeError; end
19
+
20
+ class UnshardedTableError < RuntimeError; end
21
+ end
7
22
  end
@@ -5,21 +5,19 @@ module Switchman
5
5
  module Relation
6
6
  def exec_queries(*args)
7
7
  if lock_value
8
- db = Shard.current(connection_classes).database_server
9
- return db.unguard { super } if ::GuardRail.environment != db.guard_rail_environment
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|
16
+ arg_params = (RUBY_VERSION <= "2.8") ? "*args" : "*args, **kwargs"
15
17
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
16
- def #{method}(*args)
17
- db = Shard.current(connection_classes).database_server
18
- if ::GuardRail.environment != db.guard_rail_environment
19
- db.unguard { super }
20
- else
21
- super
22
- end
18
+ def #{method}(#{arg_params})
19
+ db = Shard.current(connection_class_for_self).database_server
20
+ db.unguard { super }
23
21
  end
24
22
  RUBY
25
23
  end
@@ -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)
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'switchman/test_helper'
3
+ require "switchman/test_helper"
4
4
 
5
5
  module Switchman
6
6
  # including this module in your specs will give you several shards to
@@ -34,9 +34,9 @@ module Switchman
34
34
  groups = group.class.descendant_filtered_examples.map(&:example_group).uniq
35
35
  next unless groups.any? { |descendant_group| RSpecHelper.included_in?(descendant_group) }
36
36
 
37
- puts 'Setting up sharding for all specs...'
37
+ puts "Setting up sharding for all specs..."
38
38
  Shard.delete_all
39
- Switchman.cache.delete('default_shard')
39
+ Switchman.cache.delete("default_shard")
40
40
 
41
41
  @@shard1, @@shard2 = TestHelper.recreate_persistent_test_shards
42
42
  @@default_shard = Shard.default
@@ -48,7 +48,7 @@ module Switchman
48
48
  @@shard1 = @@shard1.create_new_shard
49
49
  @@shard2 = @@shard2.create_new_shard
50
50
  rescue => e
51
- warn 'Sharding setup FAILED!:'
51
+ warn "Sharding setup FAILED!:"
52
52
  while e
53
53
  warn "\n#{e}\n"
54
54
  warn e.backtrace
@@ -66,14 +66,17 @@ module Switchman
66
66
  # we'll re-persist in the group's `before :all`; we don't want them to exist
67
67
  # in the db before then
68
68
  Shard.delete_all
69
- Switchman.cache.delete('default_shard')
69
+ Switchman.cache.delete("default_shard")
70
70
  Shard.default(reload: true)
71
- puts 'Done!'
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
- puts 'Tearing down sharding for all specs'
79
+ puts "Tearing down sharding for all specs"
77
80
  @@shard1.database_server.destroy unless @@shard1.database_server == Shard.default.database_server
78
81
  unless @@keep_the_shards
79
82
  @@shard1.drop_database
@@ -92,7 +95,7 @@ module Switchman
92
95
  dup = @@default_shard.dup
93
96
  dup.id = @@default_shard.id
94
97
  dup.save!
95
- Switchman.cache.delete('default_shard')
98
+ Switchman.cache.delete("default_shard")
96
99
  Shard.default(reload: true)
97
100
  dup = @@shard1.dup
98
101
  dup.id = @@shard1.id
@@ -104,7 +107,7 @@ module Switchman
104
107
  end
105
108
 
106
109
  klass.before do
107
- raise 'Sharding did not set up correctly' if @@sharding_failed
110
+ raise "Sharding did not set up correctly" if @@sharding_failed
108
111
 
109
112
  Shard.clear_cache
110
113
  if use_transactional_tests
@@ -118,7 +121,7 @@ module Switchman
118
121
  next if @@sharding_failed
119
122
 
120
123
  # clean up after specs
121
- DatabaseServer.all.each do |ds|
124
+ DatabaseServer.each do |ds|
122
125
  if ds.fake? && ds != @shard2.database_server
123
126
  ds.shards.delete_all unless use_transactional_tests
124
127
  ds.destroy
@@ -129,7 +132,7 @@ module Switchman
129
132
  klass.after(:all) do
130
133
  # Don't truncate because that can create some fun cross-connection lock contention
131
134
  Shard.delete_all
132
- Switchman.cache.delete('default_shard')
135
+ Switchman.cache.delete("default_shard")
133
136
  Shard.default(reload: true)
134
137
  end
135
138
  end
@@ -4,16 +4,13 @@ module Switchman
4
4
  module Rails
5
5
  module ClassMethods
6
6
  def self.prepended(klass)
7
- # in Rails 4+, the Rails.cache= method was used during bootstrap to set
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
14
11
 
15
12
  def cache
16
- Switchman::Shard.current ? Switchman::Shard.current.database_server.cache_store : super
13
+ Switchman::Shard.current.database_server.cache_store
17
14
  end
18
15
  end
19
16
  end