switchman 3.0.24 → 4.2.4

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 (49) 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/active_record/abstract_adapter.rb +11 -7
  6. data/lib/switchman/active_record/associations.rb +157 -50
  7. data/lib/switchman/active_record/attribute_methods.rb +192 -101
  8. data/lib/switchman/active_record/base.rb +136 -33
  9. data/lib/switchman/active_record/calculations.rb +91 -48
  10. data/lib/switchman/active_record/connection_handler.rb +18 -0
  11. data/lib/switchman/active_record/connection_pool.rb +41 -6
  12. data/lib/switchman/active_record/database_configurations.rb +23 -13
  13. data/lib/switchman/active_record/finder_methods.rb +22 -16
  14. data/lib/switchman/active_record/log_subscriber.rb +3 -6
  15. data/lib/switchman/active_record/migration.rb +42 -17
  16. data/lib/switchman/active_record/model_schema.rb +1 -1
  17. data/lib/switchman/active_record/pending_migration_connection.rb +17 -0
  18. data/lib/switchman/active_record/persistence.rb +32 -2
  19. data/lib/switchman/active_record/postgresql_adapter.rb +37 -22
  20. data/lib/switchman/active_record/predicate_builder.rb +2 -2
  21. data/lib/switchman/active_record/query_cache.rb +26 -17
  22. data/lib/switchman/active_record/query_methods.rb +249 -142
  23. data/lib/switchman/active_record/reflection.rb +10 -3
  24. data/lib/switchman/active_record/relation.rb +103 -32
  25. data/lib/switchman/active_record/spawn_methods.rb +3 -7
  26. data/lib/switchman/active_record/statement_cache.rb +13 -9
  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 +71 -25
  30. data/lib/switchman/active_support/cache.rb +9 -4
  31. data/lib/switchman/arel.rb +16 -25
  32. data/lib/switchman/call_super.rb +2 -2
  33. data/lib/switchman/database_server.rb +68 -34
  34. data/lib/switchman/default_shard.rb +14 -3
  35. data/lib/switchman/engine.rb +36 -19
  36. data/lib/switchman/environment.rb +2 -2
  37. data/lib/switchman/errors.rb +13 -0
  38. data/lib/switchman/guard_rail/relation.rb +3 -3
  39. data/lib/switchman/parallel.rb +6 -6
  40. data/lib/switchman/r_spec_helper.rb +12 -11
  41. data/lib/switchman/shard.rb +182 -72
  42. data/lib/switchman/sharded_instrumenter.rb +9 -3
  43. data/lib/switchman/shared_schema_cache.rb +11 -0
  44. data/lib/switchman/standard_error.rb +4 -0
  45. data/lib/switchman/test_helper.rb +3 -3
  46. data/lib/switchman/version.rb +1 -1
  47. data/lib/switchman.rb +27 -15
  48. data/lib/tasks/switchman.rake +96 -60
  49. metadata +18 -168
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'securerandom'
3
+ require "securerandom"
4
4
 
5
5
  module Switchman
6
6
  class DatabaseServer
@@ -10,19 +10,23 @@ module Switchman
10
10
  attr_accessor :creating_new_shard
11
11
  attr_reader :all_roles
12
12
 
13
+ include Enumerable
14
+
15
+ delegate :each, to: :all
16
+
13
17
  def all
14
18
  database_servers.values
15
19
  end
16
20
 
17
21
  def find(id_or_all)
18
22
  return all if id_or_all == :all
19
- return id_or_all.map { |id| database_servers[id || ::Rails.env] }.compact.uniq if id_or_all.is_a?(Array)
23
+ return id_or_all.filter_map { |id| database_servers[id || ::Rails.env] }.uniq if id_or_all.is_a?(Array)
20
24
 
21
25
  database_servers[id_or_all || ::Rails.env]
22
26
  end
23
27
 
24
28
  def create(settings = {})
25
- raise 'database servers should be set up in database.yml' unless ::Rails.env.test?
29
+ raise "database servers should be set up in database.yml" unless ::Rails.env.test?
26
30
 
27
31
  id = settings[:id]
28
32
  unless id
@@ -50,6 +54,10 @@ module Switchman
50
54
  all.each { |db| db.guard! if db.config[:prefer_secondary] }
51
55
  end
52
56
 
57
+ def regions
58
+ @regions ||= all.filter_map(&:region).uniq.sort
59
+ end
60
+
53
61
  private
54
62
 
55
63
  def reference_role(role)
@@ -64,8 +72,8 @@ module Switchman
64
72
  @database_servers = {}.with_indifferent_access
65
73
  roles = []
66
74
  ::ActiveRecord::Base.configurations.configurations.each do |config|
67
- if config.name.include?('/')
68
- name, role = config.name.split('/')
75
+ if config.name.include?("/")
76
+ name, role = config.name.split("/")
69
77
  else
70
78
  name, role = config.env_name, config.name
71
79
  end
@@ -81,6 +89,8 @@ module Switchman
81
89
  # Do this after so that all database servers for all roles are established and we won't prematurely
82
90
  # configure a connection for the wrong role
83
91
  @all_roles = roles.uniq
92
+ return @database_servers if @database_servers.empty?
93
+
84
94
  Shard.send(:configure_connects_to)
85
95
  end
86
96
  @database_servers
@@ -110,8 +120,9 @@ module Switchman
110
120
  self.class.send(:database_servers).delete(id) if id
111
121
  Shard.sharded_models.each do |klass|
112
122
  self.class.all_roles.each do |role|
113
- klass.connection_handler.remove_connection_pool(klass.connection_specification_name, role: role,
114
- shard: id.to_sym)
123
+ klass.connection_handler.remove_connection_pool(klass.connection_specification_name,
124
+ role:,
125
+ shard: id.to_sym)
115
126
  end
116
127
  end
117
128
  end
@@ -137,16 +148,41 @@ module Switchman
137
148
  end
138
149
  end
139
150
 
151
+ def region
152
+ config[:region]
153
+ end
154
+
155
+ # @param region [String, Array<String>] the region(s) to check against
156
+ # @return true if the database server doesn't have a region, or it
157
+ # matches the specified region
158
+ def in_region?(region)
159
+ !self.region || (region.is_a?(Array) ? region.include?(self.region) : self.region == region)
160
+ end
161
+
162
+ # @return true if the database server doesn't have a region, Switchman is
163
+ # not configured with a region, or the database server's region matches
164
+ # Switchman's current region
165
+ def in_current_region?
166
+ unless instance_variable_defined?(:@in_current_region)
167
+ @in_current_region = !region ||
168
+ !Switchman.region ||
169
+ region == Switchman.region
170
+ end
171
+ @in_current_region
172
+ end
173
+
140
174
  # locks this db to a specific environment, except for
141
175
  # when doing writes (then it falls back to the current
142
176
  # value of GuardRail.environment)
143
177
  def guard!(environment = :secondary)
144
178
  DatabaseServer.send(:reference_role, environment)
145
- ::ActiveRecord::Base.connected_to_stack << { shard_roles: { id.to_sym => environment }, klasses: [::ActiveRecord::Base] }
179
+ ::ActiveRecord::Base.connected_to_stack << { shard_roles: { id.to_sym => environment },
180
+ klasses: [::ActiveRecord::Base] }
146
181
  end
147
182
 
148
183
  def unguard!
149
- ::ActiveRecord::Base.connected_to_stack << { shard_roles: { id.to_sym => :_switchman_inherit }, klasses: [::ActiveRecord::Base] }
184
+ ::ActiveRecord::Base.connected_to_stack << { shard_roles: { id.to_sym => :_switchman_inherit },
185
+ klasses: [::ActiveRecord::Base] }
150
186
  end
151
187
 
152
188
  def unguard
@@ -162,7 +198,7 @@ module Switchman
162
198
 
163
199
  def shards
164
200
  if id == ::Rails.env
165
- Shard.where('database_server_id IS NULL OR database_server_id=?', id)
201
+ Shard.where("database_server_id IS NULL OR database_server_id=?", id)
166
202
  else
167
203
  Shard.where(database_server_id: id)
168
204
  end
@@ -182,12 +218,12 @@ module Switchman
182
218
  if config_create_statement
183
219
  create_commands = Array(config_create_statement).dup
184
220
  create_statement = lambda {
185
- create_commands.map { |statement| format(statement, name: name, password: password) }
221
+ create_commands.map { |statement| format(statement, name:, password:) }
186
222
  }
187
223
  end
188
224
 
189
225
  id ||= begin
190
- id_seq = Shard.connection.quote(Shard.connection.quote_table_name('switchman_shards_id_seq'))
226
+ id_seq = Shard.connection.quote(Shard.connection.quote_table_name("switchman_shards_id_seq"))
191
227
  next_id = Shard.connection.select_value("SELECT nextval(#{id_seq})")
192
228
  next_id.to_i
193
229
  end
@@ -200,33 +236,32 @@ module Switchman
200
236
  self.class.creating_new_shard = true
201
237
  DatabaseServer.send(:reference_role, :deploy)
202
238
  ::ActiveRecord::Base.connected_to(shard: self.id.to_sym, role: :deploy) do
203
- shard = Shard.create!(id: id,
204
- name: name,
239
+ shard = Shard.create!(id:,
240
+ name:,
205
241
  database_server_id: self.id)
206
242
  if create_statement
207
- if ::ActiveRecord::Base.connection.select_value("SELECT 1 FROM pg_namespace WHERE nspname=#{::ActiveRecord::Base.connection.quote(name)}")
243
+ if ::ActiveRecord::Base.connection.select_value(
244
+ "SELECT 1 FROM pg_namespace WHERE nspname=#{::ActiveRecord::Base.connection.quote(name)}"
245
+ )
208
246
  schema_already_existed = true
209
- raise 'This schema already exists; cannot overwrite'
247
+ raise "This schema already exists; cannot overwrite"
210
248
  end
211
249
  Array(create_statement.call).each do |stmt|
212
250
  ::ActiveRecord::Base.connection.execute(stmt)
213
251
  end
214
252
  end
215
- if config[:adapter] == 'postgresql'
216
- old_proc = ::ActiveRecord::Base.connection.raw_connection.set_notice_processor do
217
- end
253
+ if config[:adapter] == "postgresql"
254
+ old_proc = ::ActiveRecord::Base.connection.raw_connection.set_notice_processor {}
218
255
  end
219
256
  old_verbose = ::ActiveRecord::Migration.verbose
220
257
  ::ActiveRecord::Migration.verbose = false
221
258
 
222
259
  unless schema == false
223
260
  shard.activate do
224
- reset_column_information
225
-
226
261
  ::ActiveRecord::Base.connection.transaction(requires_new: true) do
227
- ::ActiveRecord::Base.connection.migration_context.migrate
262
+ ::ActiveRecord::MigrationContext.new(::ActiveRecord::Migrator.migrations_paths).migrate
228
263
  end
229
- reset_column_information
264
+
230
265
  ::ActiveRecord::Base.descendants.reject do |m|
231
266
  m <= UnshardedRecord || !m.table_exists?
232
267
  end.each(&:define_attribute_methods)
@@ -240,7 +275,6 @@ module Switchman
240
275
  rescue
241
276
  shard&.destroy
242
277
  shard&.drop_database rescue nil unless schema_already_existed
243
- reset_column_information unless schema == false rescue nil
244
278
  raise
245
279
  ensure
246
280
  self.class.creating_new_shard = false
@@ -265,18 +299,18 @@ module Switchman
265
299
  end
266
300
 
267
301
  def primary_shard
268
- unless instance_variable_defined?(:@primary_shard)
269
- # if sharding isn't fully set up yet, we may not be able to query the shards table
270
- @primary_shard = Shard.default if Shard.default.database_server == self
271
- @primary_shard ||= shards.where(name: nil).first
272
- end
273
- @primary_shard
274
- end
302
+ return nil unless primary_shard_id
275
303
 
276
- private
304
+ Shard.lookup(primary_shard_id)
305
+ end
277
306
 
278
- def reset_column_information
279
- ::ActiveRecord::Base.descendants.reject { |m| m <= UnshardedRecord }.each(&:reset_column_information)
307
+ def primary_shard_id
308
+ unless instance_variable_defined?(:@primary_shard_id)
309
+ # if sharding isn't fully set up yet, we may not be able to query the shards table
310
+ @primary_shard_id = Shard.default.id if Shard.default.database_server == self
311
+ @primary_shard_id ||= shards.where(name: nil).first&.id
312
+ end
313
+ @primary_shard_id
280
314
  end
281
315
  end
282
316
  end
@@ -3,9 +3,10 @@
3
3
  module Switchman
4
4
  class DefaultShard
5
5
  def id
6
- 'default'
6
+ "default"
7
7
  end
8
- alias cache_key id
8
+ alias_method :cache_key, :id
9
+
9
10
  def activate(*_classes)
10
11
  yield
11
12
  end
@@ -57,8 +58,18 @@ module Switchman
57
58
  self
58
59
  end
59
60
 
61
+ def region; end
62
+
63
+ def in_region?(_region)
64
+ true
65
+ end
66
+
67
+ def in_current_region?
68
+ true
69
+ end
70
+
60
71
  def _dump(_depth)
61
- ''
72
+ ""
62
73
  end
63
74
 
64
75
  def self._load(_str)
@@ -4,27 +4,22 @@ module Switchman
4
4
  class Engine < ::Rails::Engine
5
5
  isolate_namespace Switchman
6
6
 
7
- # enable Rails 6.1 style connection handling
8
- config.active_record.legacy_connection_handling = false
9
7
  config.active_record.writing_role = :primary
10
8
 
11
9
  ::GuardRail.singleton_class.prepend(GuardRail::ClassMethods)
12
10
 
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
- initialize_dependency_mechanism = ::Rails::Application::Bootstrap.initializers.find { |i| i.name == :initialize_dependency_mechanism }
16
- initialize_dependency_mechanism.instance_variable_get(:@options)[:after] = :set_autoload_paths
17
-
18
- initializer 'switchman.active_record_patch', before: 'active_record.initialize_database', after: :initialize_dependency_mechanism do
11
+ initializer "switchman.active_record_patch",
12
+ before: "active_record.initialize_database",
13
+ after: :setup_once_autoloader do
19
14
  ::ActiveSupport.on_load(:active_record) do
20
15
  # Switchman requires postgres, so just always load the pg adapter
21
- require 'active_record/connection_adapters/postgresql_adapter'
16
+ require "active_record/connection_adapters/postgresql_adapter"
22
17
 
23
18
  self.default_shard = ::Rails.env.to_sym
24
19
  self.default_role = :primary
25
20
 
26
21
  prepend ActiveRecord::Base
27
- include ActiveRecord::AttributeMethods
22
+ prepend ActiveRecord::AttributeMethods
28
23
  include ActiveRecord::Persistence
29
24
  singleton_class.prepend ActiveRecord::ModelSchema::ClassMethods
30
25
 
@@ -46,13 +41,27 @@ module Switchman
46
41
  ::ActiveRecord::Associations::CollectionProxy.include(ActiveRecord::Associations::CollectionProxy)
47
42
 
48
43
  ::ActiveRecord::Associations::Preloader::Association.prepend(ActiveRecord::Associations::Preloader::Association)
44
+ ::ActiveRecord::Associations::Preloader::Association::LoaderRecords.prepend(
45
+ ActiveRecord::Associations::Preloader::Association::LoaderRecords
46
+ )
49
47
  ::ActiveRecord::ConnectionAdapters::AbstractAdapter.prepend(ActiveRecord::AbstractAdapter)
48
+ ::ActiveRecord::ConnectionAdapters::ConnectionHandler.prepend(ActiveRecord::ConnectionHandler)
50
49
  ::ActiveRecord::ConnectionAdapters::ConnectionPool.prepend(ActiveRecord::ConnectionPool)
51
50
  ::ActiveRecord::ConnectionAdapters::AbstractAdapter.prepend(ActiveRecord::QueryCache)
52
51
  ::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.prepend(ActiveRecord::PostgreSQLAdapter)
52
+ # https://github.com/rails/rails/commit/0016280f4fde55d96738887093dc333aae0d107b
53
+ if ::Rails.version < "7.2"
54
+ ::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.prepend(ActiveRecord::PostgreSQLAdapter::ClassMethods)
55
+ else
56
+ ::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.singleton_class.prepend(
57
+ ActiveRecord::PostgreSQLAdapter::ClassMethods
58
+ )
59
+ end
53
60
 
54
61
  ::ActiveRecord::DatabaseConfigurations.prepend(ActiveRecord::DatabaseConfigurations)
55
- ::ActiveRecord::DatabaseConfigurations::DatabaseConfig.prepend(ActiveRecord::DatabaseConfigurations::DatabaseConfig)
62
+ ::ActiveRecord::DatabaseConfigurations::DatabaseConfig.prepend(
63
+ ActiveRecord::DatabaseConfigurations::DatabaseConfig
64
+ )
56
65
 
57
66
  ::ActiveRecord::LogSubscriber.prepend(ActiveRecord::LogSubscriber)
58
67
  ::ActiveRecord::Migration.prepend(ActiveRecord::Migration)
@@ -60,6 +69,11 @@ module Switchman
60
69
  ::ActiveRecord::MigrationContext.prepend(ActiveRecord::MigrationContext)
61
70
  ::ActiveRecord::Migrator.prepend(ActiveRecord::Migrator)
62
71
 
72
+ if ::Rails.version > "7.1.3"
73
+ ::ActiveRecord::PendingMigrationConnection.singleton_class
74
+ .include(ActiveRecord::PendingMigrationConnection::ClassMethods)
75
+ end
76
+
63
77
  ::ActiveRecord::Reflection::AbstractReflection.include(ActiveRecord::Reflection::AbstractReflection)
64
78
  ::ActiveRecord::Reflection::AssociationReflection.prepend(ActiveRecord::Reflection::AssociationScopeCache)
65
79
  ::ActiveRecord::Reflection::ThroughReflection.prepend(ActiveRecord::Reflection::AssociationScopeCache)
@@ -69,11 +83,13 @@ module Switchman
69
83
  ::ActiveRecord::Relation.include(ActiveRecord::QueryMethods)
70
84
  ::ActiveRecord::Relation.prepend(GuardRail::Relation)
71
85
  ::ActiveRecord::Relation.prepend(ActiveRecord::Relation)
86
+ ::ActiveRecord::Relation.prepend(ActiveRecord::Relation::InsertUpsertAll) if ::Rails.version >= "7.2"
72
87
  ::ActiveRecord::Relation.include(ActiveRecord::SpawnMethods)
73
88
  ::ActiveRecord::Relation.include(CallSuper)
74
89
 
75
- ::ActiveRecord::PredicateBuilder::AssociationQueryValue.prepend(ActiveRecord::PredicateBuilder::AssociationQueryValue)
76
- ::ActiveRecord::PredicateBuilder::PolymorphicArrayValue.prepend(ActiveRecord::PredicateBuilder::AssociationQueryValue)
90
+ ::ActiveRecord::PredicateBuilder::PolymorphicArrayValue.prepend(
91
+ ActiveRecord::PredicateBuilder::PolymorphicArrayValue
92
+ )
77
93
 
78
94
  ::ActiveRecord::Tasks::DatabaseTasks.singleton_class.prepend(ActiveRecord::Tasks::DatabaseTasks)
79
95
 
@@ -91,17 +107,18 @@ module Switchman
91
107
 
92
108
  ::ActiveRecord::ConnectionAdapters::TableDefinition.prepend(ActiveRecord::TableDefinition)
93
109
  end
94
- # Ensure that ActiveRecord::Base is always loaded before any app-level initializers can go try to load Switchman::Shard or we get a loop
110
+ # Ensure that ActiveRecord::Base is always loaded before any app-level
111
+ # initializers can go try to load Switchman::Shard or we get a loop
95
112
  ::ActiveRecord::Base
96
113
  end
97
114
 
98
- initializer 'switchman.error_patch', after: 'active_record.initialize_database' do
115
+ initializer "switchman.error_patch", after: "active_record.initialize_database" do
99
116
  ::ActiveSupport.on_load(:active_record) do
100
117
  ::StandardError.include(StandardError)
101
118
  end
102
119
  end
103
120
 
104
- initializer 'switchman.initialize_cache', before: :initialize_cache, after: 'active_record.initialize_database' do
121
+ initializer "switchman.initialize_cache", before: :initialize_cache, after: "active_record.initialize_database" do
105
122
  ::ActiveSupport::Cache.singleton_class.prepend(ActiveSupport::Cache::ClassMethods)
106
123
 
107
124
  # if we haven't already setup our cache map out-of-band, set it up from
@@ -125,11 +142,11 @@ module Switchman
125
142
  Switchman.config[:cache_map][::Rails.env] = value
126
143
  end
127
144
 
128
- middlewares = Switchman.config[:cache_map].values.map do |store|
145
+ middlewares = Switchman.config[:cache_map].values.filter_map do |store|
129
146
  store.middleware if store.respond_to?(:middleware)
130
- end.compact.uniq
147
+ end.uniq
131
148
  middlewares.each do |middleware|
132
- config.middleware.insert_before('Rack::Runtime', middleware)
149
+ config.middleware.insert_before("Rack::Runtime", middleware)
133
150
  end
134
151
 
135
152
  # prevent :initialize_cache from trying to (or needing to) set
@@ -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
@@ -2,8 +2,21 @@
2
2
 
3
3
  module Switchman
4
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."
8
+
9
+ def initialize(msg = DEFAULT_MSG)
10
+ super
11
+ end
12
+ end
13
+
5
14
  class NonExistentShardError < RuntimeError; end
6
15
 
7
16
  class ParallelShardExecError < RuntimeError; end
17
+
18
+ class ShadowRecordError < RuntimeError; end
19
+
20
+ class UnshardedTableError < RuntimeError; end
8
21
  end
9
22
  end
@@ -5,7 +5,7 @@ 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
8
+ db = Shard.current(connection_class_for_self).database_server
9
9
  db.unguard { super }
10
10
  else
11
11
  super
@@ -14,8 +14,8 @@ module Switchman
14
14
 
15
15
  %w[update_all delete_all].each do |method|
16
16
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
17
- def #{method}(*args)
18
- db = Shard.current(connection_classes).database_server
17
+ def #{method}(*args, **kwargs)
18
+ db = Shard.current(connection_class_for_self).database_server
19
19
  db.unguard { super }
20
20
  end
21
21
  RUBY
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'parallel'
3
+ require "parallel"
4
4
 
5
5
  module Switchman
6
6
  module Parallel
@@ -50,19 +50,19 @@ module Switchman
50
50
  end
51
51
  end
52
52
 
53
- class PrefixingIO
53
+ class TransformingIO
54
54
  delegate_missing_to :@original_io
55
55
 
56
- def initialize(prefix, original_io)
57
- @prefix = prefix
56
+ def initialize(transformer, original_io)
57
+ @transformer = transformer
58
58
  @original_io = original_io
59
59
  end
60
60
 
61
61
  def puts(*args)
62
- args.flatten.each { |arg| @original_io.puts "#{@prefix}: #{arg}" }
62
+ args.flatten.each { |arg| @original_io.puts @transformer.call(arg) }
63
63
  end
64
64
  end
65
65
  end
66
66
  end
67
67
 
68
- ::Parallel::UndumpableException.prepend(::Switchman::Parallel::UndumpableException)
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,9 +66,9 @@ 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
73
  main_pid = Process.pid
74
74
  at_exit do
@@ -76,7 +76,7 @@ module Switchman
76
76
 
77
77
  # preserve rspec's exit status
78
78
  status = $!.is_a?(::SystemExit) ? $!.status : nil
79
- puts 'Tearing down sharding for all specs'
79
+ puts "Tearing down sharding for all specs"
80
80
  @@shard1.database_server.destroy unless @@shard1.database_server == Shard.default.database_server
81
81
  unless @@keep_the_shards
82
82
  @@shard1.drop_database
@@ -95,7 +95,7 @@ module Switchman
95
95
  dup = @@default_shard.dup
96
96
  dup.id = @@default_shard.id
97
97
  dup.save!
98
- Switchman.cache.delete('default_shard')
98
+ Switchman.cache.delete("default_shard")
99
99
  Shard.default(reload: true)
100
100
  dup = @@shard1.dup
101
101
  dup.id = @@shard1.id
@@ -107,7 +107,7 @@ module Switchman
107
107
  end
108
108
 
109
109
  klass.before do
110
- raise 'Sharding did not set up correctly' if @@sharding_failed
110
+ raise "Sharding did not set up correctly" if @@sharding_failed
111
111
 
112
112
  Shard.clear_cache
113
113
  if use_transactional_tests
@@ -121,18 +121,19 @@ module Switchman
121
121
  next if @@sharding_failed
122
122
 
123
123
  # clean up after specs
124
- DatabaseServer.all.each do |ds|
124
+ DatabaseServer.each do |ds|
125
125
  if ds.fake? && ds != @shard2.database_server
126
126
  ds.shards.delete_all unless use_transactional_tests
127
127
  ds.destroy
128
128
  end
129
+ ds.remove_instance_variable(:@primary_shard_id) if ds.instance_variable_defined?(:@primary_shard_id)
129
130
  end
130
131
  end
131
132
 
132
133
  klass.after(:all) do
133
134
  # Don't truncate because that can create some fun cross-connection lock contention
134
135
  Shard.delete_all
135
- Switchman.cache.delete('default_shard')
136
+ Switchman.cache.delete("default_shard")
136
137
  Shard.default(reload: true)
137
138
  end
138
139
  end