class GlobalUid::Server

Attributes

allocators[RW]
connection[RW]
connection_retry[RW]
connection_timeout[RW]
increment_by[RW]
name[RW]
query_timeout[RW]
retry_at[RW]

Public Class Methods

new(name, increment_by:, connection_retry:, connection_timeout:, query_timeout:) click to toggle source
# File lib/global_uid/server.rb, line 6
def initialize(name, increment_by:, connection_retry:, connection_timeout:, query_timeout:)
  @connection = nil
  @name = name
  @retry_at = nil
  @allocators = {}
  @increment_by = increment_by
  @connection_retry = connection_retry
  @connection_timeout = connection_timeout
  @query_timeout = query_timeout
end

Public Instance Methods

active?() click to toggle source
# File lib/global_uid/server.rb, line 31
def active?
  !disconnected?
end
allocate(klass, count: 1) click to toggle source
# File lib/global_uid/server.rb, line 67
def allocate(klass, count: 1)
  # TODO: Replace Timeout.timeout with DB level timeout
  #   Timeout.timeout is unpredictable
  Timeout.timeout(query_timeout, TimeoutException) do
    if count == 1
      allocator(klass).allocate_one
    else
      allocator(klass).allocate_many(count: count)
    end
  end
end
connect() click to toggle source
# File lib/global_uid/server.rb, line 17
def connect
  return @connection if active? || !retry_connection?
  @connection = mysql2_connection(name)

  begin
    validate_connection_increment if active?
  rescue InvalidIncrementException => e
    GlobalUid.configuration.notifier.call(e)
    disconnect!
  end

  @connection
end
create_uid_table!(name:, uid_type: nil, start_id: nil) click to toggle source
# File lib/global_uid/server.rb, line 48
def create_uid_table!(name:, uid_type: nil, start_id: nil)
  uid_type ||= "bigint(21) UNSIGNED"
  start_id ||= 1

  connection.execute("CREATE TABLE IF NOT EXISTS `#{name}` (
  `id` #{uid_type} NOT NULL AUTO_INCREMENT,
  `stub` char(1) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  UNIQUE KEY `stub` (`stub`)
  ) ENGINE=#{GlobalUid.configuration.storage_engine}")

  # prime the pump on each server
  connection.execute("INSERT IGNORE INTO `#{name}` VALUES(#{start_id}, 'a')")
end
disconnect!() click to toggle source
# File lib/global_uid/server.rb, line 43
def disconnect!
  @connection = nil
  @allocators = {}
end
disconnected?() click to toggle source
# File lib/global_uid/server.rb, line 35
def disconnected?
  @connection.nil?
end
drop_uid_table!(name:) click to toggle source
# File lib/global_uid/server.rb, line 63
def drop_uid_table!(name:)
  connection.execute("DROP TABLE IF EXISTS `#{name}`")
end
update_retry_at(seconds) click to toggle source
# File lib/global_uid/server.rb, line 39
def update_retry_at(seconds)
  @retry_at = Time.now + seconds
end

Private Instance Methods

allocator(klass) click to toggle source
# File lib/global_uid/server.rb, line 83
def allocator(klass)
  table_name = klass.global_uid_table
  @allocators[table_name] ||= Allocator.new(incrementing_by: increment_by, connection: connection, table_name: table_name)
end
mysql2_config(name) click to toggle source
# File lib/global_uid/server.rb, line 110
def mysql2_config(name)
  raise "No id server '#{name}' configured in database.yml" unless ActiveRecord::Base.configurations.to_h.has_key?(name)
  config = ActiveRecord::Base.configurations.to_h[name]

  c = config.symbolize_keys
  raise "No global_uid support for adapter #{c[:adapter]}" if c[:adapter] != 'mysql2'

  config
end
mysql2_connection(name) click to toggle source
# File lib/global_uid/server.rb, line 95
def mysql2_connection(name)
  config = mysql2_config(name)

  Timeout.timeout(connection_timeout, ConnectionTimeoutException) do
    ActiveRecord::Base.mysql2_connection(config)
  end
rescue ConnectionTimeoutException => e
  GlobalUid.configuration.notifier.call(ConnectionTimeoutException.new("Timed out establishing a connection to #{name}"))
  nil
rescue Exception => e
  GlobalUid.configuration.notifier.call(StandardError.new("establishing a connection to #{name}: #{e.message}"))
  nil
end
retry_connection?() click to toggle source
# File lib/global_uid/server.rb, line 88
def retry_connection?
  return Time.now > retry_at if retry_at

  update_retry_at(connection_retry)
  true
end
validate_connection_increment() click to toggle source
# File lib/global_uid/server.rb, line 130
def validate_connection_increment
  db_increment = connection.select_value("SELECT @@auto_increment_increment")

  if db_increment != increment_by
    GlobalUid::Base.alert(InvalidIncrementException.new("Configured: '#{increment_by}', Found: '#{db_increment}' on '#{connection.current_database}'"))
  end
end