global_uid 3.7.1 → 4.0.0.beta1

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 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