global_uid 3.7.1 → 4.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 66c3d7277c02d403b85ba5a0c89357d1fa23d3c80817678226fc9e0ffd945e99
4
- data.tar.gz: a922b9dfec3c753668e4cf5b14fbc2c795cb0d57b7d728fbbd85f5a725e18ada
3
+ metadata.gz: 0a02789fdd302a6dbc207c590c60ce5b5909f8430e3432813af90d0373efd71b
4
+ data.tar.gz: 4cf5cd96f7b8855b546a1741c67dac5db6bb9b42cca3105bbe741423a2f2e66e
5
5
  SHA512:
6
- metadata.gz: f3101805f0c413c2ece2aba4cab83e890e9bc4966304074cb21fea7f12ba0ba5f9f7d6d50ae89ceae81c8178f5717f3791151c14c8f41da3aebc858f2a9a7278
7
- data.tar.gz: c575ec0cd1cd707bfb7aa18e4acad03fc4423a070553dc5b1d06288f0d541084efaaca12fc60144461b45538ce0a369ba564899500604e6c58e3191130efd689
6
+ metadata.gz: 9e36b732bbea40d81423498b9ec9365e39688601691524b615a9b1cc0955b5dbcbf7b9788128bcb5673b08ccd37c49b44a7990d8a62f578358cd9ca8116d17fb
7
+ data.tar.gz: 73b1d6ff9808d94c14e1618b7da2137e0ad9c2b02442941b788519ebdc77daec7bfc8be67715ec16294062ea8ae334c1b437a198342f096623bd4f124585385c
@@ -1,5 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
  require "global_uid/base"
3
+ require "global_uid/allocator"
4
+ require "global_uid/server"
5
+ require "global_uid/configuration"
6
+ require "global_uid/error_tracker"
3
7
  require "global_uid/active_record_extension"
4
8
  require "global_uid/has_and_belongs_to_many_builder_extension"
5
9
  require "global_uid/migration_extension"
@@ -9,8 +13,20 @@ module GlobalUid
9
13
  class NoServersAvailableException < StandardError ; end
10
14
  class ConnectionTimeoutException < StandardError ; end
11
15
  class TimeoutException < StandardError ; end
16
+ class InvalidIncrementException < StandardError ; end
12
17
 
13
- autoload :ServerVariables, "global_uid/server_variables"
18
+ def self.configuration
19
+ @configuration ||= GlobalUid::Configuration.new
20
+ end
21
+
22
+ def self.configure
23
+ yield configuration if block_given?
24
+ end
25
+
26
+ # @private
27
+ def self.reset_configuration
28
+ @configuration = nil
29
+ end
14
30
  end
15
31
 
16
32
  ActiveRecord::Base.send(:include, GlobalUid::ActiveRecordExtension)
@@ -26,10 +42,5 @@ if ActiveRecord::VERSION::MAJOR >= 5
26
42
  ActiveRecord::InternalMetadata.disable_global_uid
27
43
  end
28
44
 
29
- if ActiveRecord::VERSION::STRING >= '4.1.0'
30
- ActiveRecord::Associations::Builder::HasAndBelongsToMany.send(:include, GlobalUid::HasAndBelongsToManyBuilderExtension)
31
- end
32
-
33
- if ActiveRecord::VERSION::MAJOR >= 4
34
- ActiveRecord::SchemaDumper.send(:prepend, GlobalUid::SchemaDumperExtension)
35
- end
45
+ ActiveRecord::Associations::Builder::HasAndBelongsToMany.send(:include, GlobalUid::HasAndBelongsToManyBuilderExtension)
46
+ ActiveRecord::SchemaDumper.send(:prepend, GlobalUid::SchemaDumperExtension)
@@ -8,20 +8,10 @@ module GlobalUid
8
8
  end
9
9
 
10
10
  def global_uid_before_create
11
- return if GlobalUid::Base.global_uid_options[:disabled]
11
+ return if GlobalUid.configuration.disabled?
12
12
  return if self.class.global_uid_disabled
13
13
 
14
- global_uid = nil
15
- realtime = Benchmark::realtime do
16
- global_uid = self.class.generate_uid
17
- end
18
-
19
- if GlobalUid::Base.global_uid_options[:dry_run]
20
- ActiveRecord::Base.logger.info("GlobalUid dry-run: #{self.class.name}\t#{global_uid}\t#{"%.4f" % realtime}")
21
- return
22
- end
23
-
24
- self.id = global_uid
14
+ self.id = self.class.generate_uid
25
15
  end
26
16
 
27
17
  module ClassMethods
@@ -37,12 +27,16 @@ module GlobalUid
37
27
  @global_uid_disabled
38
28
  end
39
29
 
40
- def generate_uid(options = {})
41
- GlobalUid::Base.get_uid_for_class(self, options)
30
+ def generate_uid
31
+ GlobalUid::Base.with_servers do |server|
32
+ return server.allocate(self)
33
+ end
42
34
  end
43
35
 
44
- def generate_many_uids(count, options = {})
45
- GlobalUid::Base.get_many_uids_for_class(self, count, options)
36
+ def generate_many_uids(count)
37
+ GlobalUid::Base.with_servers do |server|
38
+ return server.allocate(self, count: count)
39
+ end
46
40
  end
47
41
 
48
42
  def disable_global_uid
@@ -0,0 +1,69 @@
1
+ module GlobalUid
2
+ class Allocator
3
+ attr_reader :recent_allocations, :max_window_size, :incrementing_by, :connection
4
+
5
+ def initialize(incrementing_by:, connection:)
6
+ @recent_allocations = []
7
+ @max_window_size = 5
8
+ @incrementing_by = incrementing_by
9
+ @connection = connection
10
+ validate_connection_increment
11
+ end
12
+
13
+ def allocate_one(table)
14
+ identifier = connection.insert("REPLACE INTO #{table} (stub) VALUES ('a')")
15
+ allocate(identifier)
16
+ end
17
+
18
+ def allocate_many(table, count:)
19
+ return [] unless count > 0
20
+
21
+ increment_by = validate_connection_increment
22
+
23
+ start_id = connection.insert("REPLACE INTO #{table} (stub) VALUES " + (["('a')"] * count).join(','))
24
+ identifiers = start_id.step(start_id + (count - 1) * increment_by, increment_by).to_a
25
+ identifiers.each { |identifier| allocate(identifier) }
26
+ identifiers
27
+ end
28
+
29
+ private
30
+
31
+ def allocate(identifier)
32
+ recent_allocations.shift if recent_allocations.size >= max_window_size
33
+ recent_allocations << identifier
34
+
35
+ if !valid_allocation?
36
+ db_increment = connection.select_value("SELECT @@auto_increment_increment")
37
+ message = "Configured: '#{incrementing_by}', Found: '#{db_increment}' on '#{connection.current_database}'. Recently allocated IDs: #{recent_allocations}"
38
+ alert(InvalidIncrementException.new(message))
39
+ end
40
+
41
+ identifier
42
+ end
43
+
44
+ def valid_allocation?
45
+ recent_allocations[1..-1].all? do |identifier|
46
+ (identifier > recent_allocations[0]) &&
47
+ (identifier - recent_allocations[0]) % incrementing_by == 0
48
+ end
49
+ end
50
+
51
+ def validate_connection_increment
52
+ db_increment = connection.select_value("SELECT @@auto_increment_increment")
53
+
54
+ if db_increment != incrementing_by
55
+ alert(InvalidIncrementException.new("Configured: '#{incrementing_by}', Found: '#{db_increment}' on '#{connection.current_database}'"))
56
+ end
57
+
58
+ db_increment
59
+ end
60
+
61
+ def alert(exception)
62
+ if GlobalUid.configuration.suppress_increment_exceptions?
63
+ GlobalUid.configuration.notifier.call(exception)
64
+ else
65
+ raise exception
66
+ end
67
+ end
68
+ end
69
+ end
@@ -6,17 +6,6 @@ require "timeout"
6
6
 
7
7
  module GlobalUid
8
8
  class Base
9
- GLOBAL_UID_DEFAULTS = {
10
- :connection_timeout => 3,
11
- :connection_retry => 10.minutes,
12
- :notifier => Proc.new { |exception, message| ActiveRecord::Base.logger.error("GlobalUID error: #{exception} #{message}") },
13
- :query_timeout => 10,
14
- :increment_by => 5, # This will define the maximum number of servers that you can have
15
- :disabled => false,
16
- :per_process_affinity => true,
17
- :dry_run => false
18
- }
19
-
20
9
  def self.servers
21
10
  # Thread local storage is inheritted on `fork`, include the pid
22
11
  Thread.current["global_uid_servers_#{$$}"]
@@ -26,176 +15,54 @@ module GlobalUid
26
15
  Thread.current["global_uid_servers_#{$$}"] = s
27
16
  end
28
17
 
29
- def self.create_uid_tables(id_table_name, options={})
30
- type = options[:uid_type] || "bigint(21) UNSIGNED"
31
- start_id = options[:start_id] || 1
32
-
33
- engine_stmt = "ENGINE=#{global_uid_options[:storage_engine] || "MyISAM"}"
34
-
35
- with_connections do |connection|
36
- connection.execute("CREATE TABLE IF NOT EXISTS `#{id_table_name}` (
37
- `id` #{type} NOT NULL AUTO_INCREMENT,
38
- `stub` char(1) NOT NULL DEFAULT '',
39
- PRIMARY KEY (`id`),
40
- UNIQUE KEY `stub` (`stub`)
41
- ) #{engine_stmt}")
42
-
43
- # prime the pump on each server
44
- connection.execute("INSERT IGNORE INTO `#{id_table_name}` VALUES(#{start_id}, 'a')")
45
- end
46
- end
47
-
48
- def self.drop_uid_tables(id_table_name, options={})
49
- with_connections do |connection|
50
- connection.execute("DROP TABLE IF EXISTS `#{id_table_name}`")
51
- end
52
- end
53
-
54
- def self.new_connection(name, connection_timeout, offset, increment_by)
55
- raise "No id server '#{name}' configured in database.yml" unless ActiveRecord::Base.configurations.to_h.has_key?(name)
56
- config = ActiveRecord::Base.configurations.to_h[name]
57
- c = config.symbolize_keys
58
-
59
- raise "No global_uid support for adapter #{c[:adapter]}" if c[:adapter] != 'mysql2'
60
-
61
- begin
62
- Timeout.timeout(connection_timeout, ConnectionTimeoutException) do
63
- ActiveRecord::Base.mysql2_connection(config)
64
- end
65
- rescue ConnectionTimeoutException => e
66
- notify e, "Timed out establishing a connection to #{name}"
67
- nil
68
- rescue Exception => e
69
- notify e, "establishing a connection to #{name}: #{e.message}"
70
- nil
71
- end
72
- end
73
-
74
- def self.init_server_info(options)
75
- id_servers = self.global_uid_servers
76
-
77
- raise "You haven't configured any id servers" if id_servers.nil? or id_servers.empty?
78
- raise "More servers configured than increment_by: #{id_servers.size} > #{options[:increment_by]} -- this will create duplicate IDs." if id_servers.size > options[:increment_by]
79
-
80
- offset = 1
81
-
82
- id_servers.map do |name, i|
83
- info = {}
84
- info[:cx] = nil
85
- info[:name] = name
86
- info[:retry_at] = nil
87
- info[:offset] = offset
88
- info[:rand] = rand
89
- info[:new?] = true
90
- offset +=1
91
- info
92
- end
18
+ def self.init_server_info
19
+ GlobalUid.configuration.id_servers.map do |name|
20
+ GlobalUid::Server.new(name,
21
+ increment_by: GlobalUid.configuration.increment_by,
22
+ connection_retry: GlobalUid.configuration.connection_retry,
23
+ connection_timeout: GlobalUid.configuration.connection_timeout,
24
+ query_timeout: GlobalUid.configuration.query_timeout
25
+ )
26
+ end.shuffle # so each process uses a random server
93
27
  end
94
28
 
95
29
  def self.disconnect!
30
+ servers.each(&:disconnect!) unless servers.nil?
96
31
  self.servers = nil
97
32
  end
98
33
 
99
- def self.setup_connections!(options)
100
- connection_timeout = options[:connection_timeout]
101
- increment_by = options[:increment_by]
102
-
103
- if self.servers.nil?
104
- self.servers = init_server_info(options)
105
- # sorting here sets up each process to have affinity to a particular server.
106
- self.servers = self.servers.sort_by { |s| s[:rand] }
107
- end
108
-
109
- self.servers.each do |info|
110
- next if info[:cx]
111
-
112
- if info[:new?] || ( info[:retry_at] && Time.now > info[:retry_at] )
113
- info[:new?] = false
114
-
115
- connection = new_connection(info[:name], connection_timeout, info[:offset], increment_by)
116
- info[:cx] = connection
117
- info[:retry_at] = Time.now + options[:connection_retry] if connection.nil?
118
- end
119
- end
120
-
121
- self.servers
122
- end
123
-
124
- def self.with_connections(options = {})
125
- options = self.global_uid_options.merge(options)
126
- servers = setup_connections!(options)
34
+ def self.with_servers
35
+ self.servers ||= init_server_info
36
+ servers = self.servers.each(&:connect)
127
37
 
128
- if !options[:per_process_affinity]
129
- servers = servers.sort_by { rand } #yes, I know it's not true random.
38
+ if GlobalUid.configuration.connection_shuffling?
39
+ servers.shuffle! # subsequent requests are made against different servers
130
40
  end
131
41
 
132
- raise NoServersAvailableException if servers.empty?
133
-
134
42
  errors = []
135
- servers.each do |s|
43
+ servers.each do |server|
136
44
  begin
137
- yield s[:cx] if s[:cx]
45
+ yield server if server.active?
138
46
  rescue TimeoutException, Exception => e
139
- notify e, "#{e.message}"
47
+ GlobalUid.configuration.notifier.call(e)
140
48
  errors << e
141
- s[:cx] = nil
142
- s[:retry_at] = Time.now + 1.minute
49
+ server.disconnect!
50
+ server.update_retry_at(1.minute)
143
51
  end
144
52
  end
145
53
 
146
54
  # in the case where all servers are gone, put everyone back in.
147
- if servers.all? { |info| info[:cx].nil? }
148
- servers.each do |info|
149
- info[:retry_at] = Time.now - 5.minutes
55
+ if servers.all?(&:disconnected?)
56
+ servers.each do |server|
57
+ server.update_retry_at(0)
150
58
  end
151
- raise NoServersAvailableException, "Errors hit: #{errors.map(&:to_s).join(',')}"
59
+ message = errors.empty? ? "" : "Errors hit: #{errors.map(&:to_s).join(', ')}"
60
+ exception = NoServersAvailableException.new(message)
61
+ GlobalUid.configuration.notifier.call(exception)
62
+ raise exception
152
63
  end
153
64
 
154
- servers.map { |s| s[:cx] }.compact
155
- end
156
-
157
- def self.notify(exception, message)
158
- if self.global_uid_options[:notifier]
159
- self.global_uid_options[:notifier].call(exception, message)
160
- end
161
- end
162
-
163
- def self.get_connections(options = {})
164
- with_connections {}
165
- end
166
-
167
- def self.get_uid_for_class(klass, options = {})
168
- with_connections do |connection|
169
- Timeout.timeout(self.global_uid_options[:query_timeout], TimeoutException) do
170
- id = connection.insert("REPLACE INTO #{klass.global_uid_table} (stub) VALUES ('a')")
171
- return id
172
- end
173
- end
174
- raise NoServersAvailableException, "All global UID servers are gone!"
175
- end
176
-
177
- def self.get_many_uids_for_class(klass, count, options = {})
178
- return [] unless count > 0
179
- with_connections do |connection|
180
- Timeout.timeout(self.global_uid_options[:query_timeout], TimeoutException) do
181
- increment_by = connection.select_value("SELECT @@auto_increment_increment")
182
- start_id = connection.insert("REPLACE INTO #{klass.global_uid_table} (stub) VALUES " + (["('a')"] * count).join(','))
183
- return start_id.step(start_id + (count-1) * increment_by, increment_by).to_a
184
- end
185
- end
186
- raise NoServersAvailableException, "All global UID servers are gone!"
187
- end
188
-
189
- def self.global_uid_options=(options)
190
- @global_uid_options = GLOBAL_UID_DEFAULTS.merge(options.symbolize_keys)
191
- end
192
-
193
- def self.global_uid_options
194
- @global_uid_options
195
- end
196
-
197
- def self.global_uid_servers
198
- self.global_uid_options[:id_servers]
65
+ servers
199
66
  end
200
67
 
201
68
  def self.id_table_from_name(name)
@@ -0,0 +1,67 @@
1
+ module GlobalUid
2
+ class Configuration
3
+
4
+ attr_accessor :connection_timeout
5
+ attr_accessor :connection_retry
6
+ attr_accessor :notifier
7
+ attr_accessor :query_timeout
8
+ attr_accessor :increment_by
9
+ attr_accessor :disabled
10
+ attr_accessor :connection_shuffling
11
+ attr_accessor :suppress_increment_exceptions
12
+ attr_accessor :storage_engine
13
+
14
+ alias_method :disabled?, :disabled
15
+ alias_method :connection_shuffling?, :connection_shuffling
16
+ alias_method :suppress_increment_exceptions?, :suppress_increment_exceptions
17
+
18
+ # Set defaults
19
+ def initialize
20
+ # Timeout (in seconds) for connecting to a global UID server
21
+ @connection_timeout = 3
22
+
23
+ # Duration (in seconds) to wait before attempting another connection to UID server
24
+ @connection_retry = 600 # 10 minutes
25
+
26
+ # An object that will be notified in case of a UID server failure.
27
+ # The object is expected to respond to `#call`, which will be passed one argument of type `Exception`.
28
+ @notifier = GlobalUid::ErrorTracker.new
29
+
30
+ # Timeout (in seconds) for retrieving a global UID from a server before moving to the next server
31
+ @query_timeout = 10
32
+
33
+ # Used for validation, compared with the value on the alloc servers to prevent allocation of duplicate IDs
34
+ # NB: The value configured here does not dictate the value on your alloc server and must remain in
35
+ # sync with the value of auto_increment_increment in the database.
36
+ @increment_by = 5
37
+
38
+ # Disable GlobalUid entirely
39
+ @disabled = false
40
+
41
+ # The same allocation server is used each time `with_servers` is called
42
+ @connection_shuffling = false
43
+
44
+ # Suppress configuration validation, allowing updates to auto_increment_increment while alloc servers in use.
45
+ # The InvalidIncrementException will be swallowed and logged when suppressed
46
+ @suppress_increment_exceptions = false
47
+
48
+ # The name of the alloc DB servers, defined in your database.yml
49
+ # e.g. ["id_server_1", "id_server_2"]
50
+ @id_servers = []
51
+
52
+ # The storage engine used during GloblaUid table creation
53
+ # Supported and tested: InnoDB, MyISAM
54
+ @storage_engine = "MyISAM"
55
+ end
56
+
57
+ def id_servers=(value)
58
+ raise "More servers configured than increment_by: #{value.size} > #{increment_by} -- this will create duplicate IDs." if value.size > increment_by
59
+ @id_servers = value
60
+ end
61
+
62
+ def id_servers
63
+ raise "You haven't configured any id servers" if @id_servers.empty?
64
+ @id_servers
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,7 @@
1
+ module GlobalUid
2
+ class ErrorTracker
3
+ def call(exception)
4
+ ActiveRecord::Base.logger.error("GlobalUID error: #{exception.class} #{exception.message}")
5
+ end
6
+ end
7
+ end
@@ -3,10 +3,10 @@ module GlobalUid
3
3
  module MigrationExtension
4
4
 
5
5
  def create_table(name, options = {}, &blk)
6
- uid_enabled = !(GlobalUid::Base.global_uid_options[:disabled] || options[:use_global_uid] == false)
6
+ uid_enabled = !(GlobalUid.configuration.disabled? || options[:use_global_uid] == false)
7
7
 
8
- # rules for stripping out auto_increment -- enabled, not dry-run, and not a "PK-less" table
9
- remove_auto_increment = uid_enabled && !GlobalUid::Base.global_uid_options[:dry_run] && !(options[:id] == false)
8
+ # rules for stripping out auto_increment -- enabled and not a "PK-less" table
9
+ remove_auto_increment = uid_enabled && !(options[:id] == false)
10
10
 
11
11
  options.merge!(:id => false) if remove_auto_increment
12
12
 
@@ -17,15 +17,24 @@ module GlobalUid
17
17
 
18
18
  if uid_enabled
19
19
  id_table_name = options[:global_uid_table] || GlobalUid::Base.id_table_from_name(name)
20
- GlobalUid::Base.create_uid_tables(id_table_name, options)
20
+ GlobalUid::Base.with_servers do |server|
21
+ server.create_uid_table!(
22
+ name: id_table_name,
23
+ uid_type: options[:uid_type] || "bigint(21) UNSIGNED",
24
+ start_id: options[:start_id] || 1,
25
+ storage_engine: GlobalUid.configuration.storage_engine
26
+ )
27
+ end
21
28
  end
22
29
 
23
30
  end
24
31
 
25
32
  def drop_table(name, options = {})
26
- if !GlobalUid::Base.global_uid_options[:disabled] && options[:use_global_uid] == true
33
+ if !GlobalUid.configuration.disabled? && options[:use_global_uid] == true
27
34
  id_table_name = options[:global_uid_table] || GlobalUid::Base.id_table_from_name(name)
28
- GlobalUid::Base.drop_uid_tables(id_table_name,options)
35
+ GlobalUid::Base.with_servers do |server|
36
+ server.drop_uid_table!(name: id_table_name)
37
+ end
29
38
  end
30
39
  super(name, options)
31
40
  end
@@ -0,0 +1,106 @@
1
+ module GlobalUid
2
+ class Server
3
+
4
+ attr_accessor :connection, :name
5
+
6
+ def initialize(name, increment_by:, connection_retry:, connection_timeout:, query_timeout:)
7
+ @connection = nil
8
+ @name = name
9
+ @retry_at = nil
10
+ @allocator = nil
11
+ @increment_by = increment_by
12
+ @connection_retry = connection_retry
13
+ @connection_timeout = connection_timeout
14
+ @query_timeout = query_timeout
15
+ end
16
+
17
+ def connect
18
+ return @connection if active? || !retry_connection?
19
+ @connection = mysql2_connection(name)
20
+
21
+ begin
22
+ @allocator = Allocator.new(incrementing_by: increment_by, connection: @connection) if active?
23
+ rescue InvalidIncrementException => e
24
+ GlobalUid.configuration.notifier.call(e)
25
+ disconnect!
26
+ end
27
+
28
+ @connection
29
+ end
30
+
31
+ def active?
32
+ !disconnected?
33
+ end
34
+
35
+ def disconnected?
36
+ @connection.nil?
37
+ end
38
+
39
+ def update_retry_at(seconds)
40
+ @retry_at = Time.now + seconds
41
+ end
42
+
43
+ def disconnect!
44
+ @connection = nil
45
+ @allocator = nil
46
+ end
47
+
48
+ def create_uid_table!(name:, uid_type:, start_id:, storage_engine:)
49
+ connection.execute("CREATE TABLE IF NOT EXISTS `#{name}` (
50
+ `id` #{uid_type} NOT NULL AUTO_INCREMENT,
51
+ `stub` char(1) NOT NULL DEFAULT '',
52
+ PRIMARY KEY (`id`),
53
+ UNIQUE KEY `stub` (`stub`)
54
+ ) ENGINE=#{storage_engine}")
55
+
56
+ # prime the pump on each server
57
+ connection.execute("INSERT IGNORE INTO `#{name}` VALUES(#{start_id}, 'a')")
58
+ end
59
+
60
+ def drop_uid_table!(name:)
61
+ connection.execute("DROP TABLE IF EXISTS `#{name}`")
62
+ end
63
+
64
+ def allocate(klass, count: 1)
65
+ # TODO: Replace Timeout.timeout with DB level timeout
66
+ # Timeout.timeout is unpredictable
67
+ Timeout.timeout(query_timeout, TimeoutException) do
68
+ if count == 1
69
+ allocator.allocate_one(klass.global_uid_table)
70
+ else
71
+ allocator.allocate_many(klass.global_uid_table, count: count)
72
+ end
73
+ end
74
+ end
75
+
76
+ private
77
+
78
+ attr_accessor :connection_retry, :connection_timeout, :retry_at, :increment_by, :query_timeout, :allocator
79
+
80
+ def retry_connection?
81
+ return Time.now > retry_at if retry_at
82
+
83
+ update_retry_at(connection_retry)
84
+ true
85
+ end
86
+
87
+ def mysql2_connection(name)
88
+ raise "No id server '#{name}' configured in database.yml" unless ActiveRecord::Base.configurations.to_h.has_key?(name)
89
+ config = ActiveRecord::Base.configurations.to_h[name]
90
+ c = config.symbolize_keys
91
+
92
+ raise "No global_uid support for adapter #{c[:adapter]}" if c[:adapter] != 'mysql2'
93
+
94
+ Timeout.timeout(connection_timeout, ConnectionTimeoutException) do
95
+ ActiveRecord::Base.mysql2_connection(config)
96
+ end
97
+ rescue ConnectionTimeoutException => e
98
+ GlobalUid.configuration.notifier.call(ConnectionTimeoutException.new("Timed out establishing a connection to #{name}"))
99
+ nil
100
+ rescue Exception => e
101
+ GlobalUid.configuration.notifier.call(StandardError.new("establishing a connection to #{name}: #{e.message}"))
102
+ nil
103
+ end
104
+
105
+ end
106
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: global_uid
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.7.1
4
+ version: 4.0.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Benjamin Quorning
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2020-03-17 00:00:00.000000000 Z
14
+ date: 2020-04-28 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: activerecord
@@ -117,6 +117,20 @@ dependencies:
117
117
  - - ">="
118
118
  - !ruby/object:Gem::Version
119
119
  version: '0'
120
+ - !ruby/object:Gem::Dependency
121
+ name: minitest-line
122
+ requirement: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ type: :development
128
+ prerelease: false
129
+ version_requirements: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
120
134
  - !ruby/object:Gem::Dependency
121
135
  name: mocha
122
136
  requirement: !ruby/object:Gem::Requirement
@@ -131,6 +145,20 @@ dependencies:
131
145
  - - ">="
132
146
  - !ruby/object:Gem::Version
133
147
  version: '0'
148
+ - !ruby/object:Gem::Dependency
149
+ name: benchmark-ips
150
+ requirement: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ version: '0'
155
+ type: :development
156
+ prerelease: false
157
+ version_requirements: !ruby/object:Gem::Requirement
158
+ requirements:
159
+ - - ">="
160
+ - !ruby/object:Gem::Version
161
+ version: '0'
134
162
  - !ruby/object:Gem::Dependency
135
163
  name: bump
136
164
  requirement: !ruby/object:Gem::Requirement
@@ -159,6 +187,20 @@ dependencies:
159
187
  - - ">="
160
188
  - !ruby/object:Gem::Version
161
189
  version: '0'
190
+ - !ruby/object:Gem::Dependency
191
+ name: pry
192
+ requirement: !ruby/object:Gem::Requirement
193
+ requirements:
194
+ - - ">="
195
+ - !ruby/object:Gem::Version
196
+ version: '0'
197
+ type: :development
198
+ prerelease: false
199
+ version_requirements: !ruby/object:Gem::Requirement
200
+ requirements:
201
+ - - ">="
202
+ - !ruby/object:Gem::Version
203
+ version: '0'
162
204
  description: GUIDs for sharded models
163
205
  email:
164
206
  - bquorning@zendesk.com
@@ -170,11 +212,14 @@ extra_rdoc_files: []
170
212
  files:
171
213
  - lib/global_uid.rb
172
214
  - lib/global_uid/active_record_extension.rb
215
+ - lib/global_uid/allocator.rb
173
216
  - lib/global_uid/base.rb
217
+ - lib/global_uid/configuration.rb
218
+ - lib/global_uid/error_tracker.rb
174
219
  - lib/global_uid/has_and_belongs_to_many_builder_extension.rb
175
220
  - lib/global_uid/migration_extension.rb
176
221
  - lib/global_uid/schema_dumper_extension.rb
177
- - lib/global_uid/server_variables.rb
222
+ - lib/global_uid/server.rb
178
223
  homepage: https://github.com/zendesk/global_uid
179
224
  licenses:
180
225
  - MIT
@@ -190,11 +235,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
190
235
  version: '2.4'
191
236
  required_rubygems_version: !ruby/object:Gem::Requirement
192
237
  requirements:
193
- - - ">="
238
+ - - ">"
194
239
  - !ruby/object:Gem::Version
195
- version: '0'
240
+ version: 1.3.1
196
241
  requirements: []
197
- rubygems_version: 3.1.1
242
+ rubygems_version: 3.1.2
198
243
  signing_key:
199
244
  specification_version: 4
200
245
  summary: GUID
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
- # This module is good for testing and development, not so much for production.
3
- # Please note that this is unreliable -- if you lose your CX to the server
4
- # and auto-reconnect, you will be utterly hosed. Much better to dedicate a server
5
- # or two to the cause, and set their auto_increment_increment globally.
6
- #
7
- # You can include this module in tests like this:
8
- # GlobalUid::Base.extend(GlobalUid::ServerVariables)
9
- #
10
- module GlobalUid
11
- module ServerVariables
12
-
13
- def self.extended(base)
14
- base.singleton_class.send(:alias_method, :new_connection_without_server_variables, :new_connection)
15
- base.singleton_class.send(:alias_method, :new_connection, :new_connection_with_server_variables)
16
- end
17
-
18
- def new_connection_with_server_variables(name, connection_timeout, offset, increment_by)
19
- con = new_connection_without_server_variables(name, connection_timeout, offset, increment_by)
20
-
21
- if con
22
- con.execute("set @@auto_increment_increment = #{increment_by}")
23
- con.execute("set @@auto_increment_offset = #{offset}")
24
- end
25
-
26
- con
27
- end
28
-
29
- end
30
- end