Skip to content

Commit

Permalink
Rearrange things a bit
Browse files Browse the repository at this point in the history
  • Loading branch information
isaacseymour committed Jan 12, 2018
1 parent 19f092c commit e352e87
Show file tree
Hide file tree
Showing 12 changed files with 146 additions and 84 deletions.
20 changes: 20 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
AllCops:
TargetRubyVersion: 2.4

# Configuration parameters: CountComments, ExcludedMethods.
Metrics/BlockLength:
Max: 26

# Configuration parameters: CountComments.
Metrics/MethodLength:
Max: 18

# Offense count: 2
Style/Documentation:
Exclude:
- '**/*'

# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
# URISchemes: http, https
Metrics/LineLength:
Max: 102
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
source "https://rubygems.org"
source 'https://rubygems.org'

# Specify your gem's dependencies in es_index.gemspec
gemspec
6 changes: 3 additions & 3 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
require "bundler/gem_tasks"
require "rspec/core/rake_task"
require 'bundler/gem_tasks'
require 'rspec/core/rake_task'

RSpec::Core::RakeTask.new(:spec)

task :default => :spec
task default: :spec
6 changes: 3 additions & 3 deletions bin/console
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#!/usr/bin/env ruby

require "bundler/setup"
require "es_index"
require 'bundler/setup'
require 'es_index'

# You can add fixtures and/or initialization code here to make experimenting
# with your gem easier. You can also use a different console, if you like.

# (If you use this, don't forget to add pry to your Gemfile!)
require "pry"
require 'pry'
Pry.start
42 changes: 21 additions & 21 deletions es_index.gemspec
Original file line number Diff line number Diff line change
@@ -1,40 +1,40 @@

lib = File.expand_path("../lib", __FILE__)
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require "es_index/version"
require 'es_index/version'

Gem::Specification.new do |spec|
spec.name = "es_index"
spec.name = 'es_index'
spec.version = EsIndex::VERSION
spec.authors = ["Isaac Seymour"]
spec.email = ["i.seymour@oxon.org"]
spec.authors = ['Isaac Seymour']
spec.email = ['i.seymour@oxon.org']

spec.summary = %q{Zero-downtime (re-)indexing of ActiveRecord models into Elasticsearch.}
spec.description = %q{An index manager for Elasticsearch and ActiveRecord}
spec.homepage = "https://github.com/carwow/es_index"
spec.license = "MIT"
spec.summary = 'Zero-downtime (re-)indexing of ActiveRecord models into Elasticsearch.'
spec.description = 'An index manager for Elasticsearch and ActiveRecord'
spec.homepage = 'https://github.com/carwow/es_index'
spec.license = 'MIT'

# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
# to allow pushing to a single host or delete this section to allow pushing to any host.
if spec.respond_to?(:metadata)
spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
else
raise "RubyGems 2.0 or newer is required to protect against " \
"public gem pushes."
raise 'RubyGems 2.0 or newer is required to protect against ' \
'public gem pushes.'
end

spec.files = `git ls-files -z`.split("\x0").reject do |f|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
f.match(%r{^(test|spec|features)/})
end
spec.bindir = "exe"
spec.bindir = 'exe'
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]
spec.require_paths = ['lib']

spec.add_dependency "activesupport"
spec.add_dependency 'activesupport'

spec.add_development_dependency "bundler"
spec.add_development_dependency "pry"
spec.add_development_dependency "rubocop"
spec.add_development_dependency "rspec"
spec.add_development_dependency "rake"
spec.add_development_dependency 'bundler'
spec.add_development_dependency 'pry'
spec.add_development_dependency 'rake'
spec.add_development_dependency 'rspec'
spec.add_development_dependency 'rubocop'
end
17 changes: 0 additions & 17 deletions lib/config.rb

This file was deleted.

51 changes: 51 additions & 0 deletions lib/es_index/config.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
module EsIndex
class Config
attr_reader :client, :data_source

def initialize(
client:,
data_source:,
mapping:,
**overrides,
&index_data
)
@client = client
@data_source = data_source
@mapping = mapping
@index_data = index_data
@overrides = overrides
end

def index_data(model)
@index_data.call(model)
end

def read_alias
@read_alias ||= overrides.fetch(:read_alias) { data_source.table_name }
end

def write_alias
@write_alias ||= overrides.fetch(:write_alias) { [read_alias, 'write'].join('_') }
end

def type
@type ||= overrides.fetch(:type, read_alias.singularize)
end

def logger
return Rails.logger if defined?(Rails)
@logger ||= Logger.new(STDOUT)
end

def index_definition
{
settings: overrides.fetch(:index_settings, {}),
mappings: { type => mapping }
}
end

private

attr_reader :overrides, :mapping
end
end
69 changes: 38 additions & 31 deletions lib/es_index/index_manager.rb
Original file line number Diff line number Diff line change
@@ -1,22 +1,32 @@
module EsIndex
class IndexManager
attr_reader :config

def initialize(config)
@config = config
end

def create_index(unique_name)
full_name = [config.read_alias, unique_name].join('_')

client.indices.create(
config.client.indices.create(
index: full_name,
body: config.index_definition
)

config.client.indices.put_alias(index: full_name, name: config.write_alias)
end

def populate_index(unique_name = nil, batch_size: 3000)
index_name = if unique_name
[config.read_alias, unique_name].join('_')
else
config.write_alias
end

config.data_source.find_in_batches(batch_size: batch_size) do |batch|
indexer.index_batch(batch, index_name: index_name)
end
end

def switch_read_index(new_name)
new_index = [config.read_alias, new_name].join('_')

Expand All @@ -29,27 +39,27 @@ def switch_read_index(new_name)
({ remove: { index: old_index, alias: config.read_alias } } if old_index)

config.client.indices.update_aliases(body: {
actions: [
remove_action,
{ add: { index: new_index, alias: config.read_alias } }
].compact
})
actions: [
remove_action,
{ add: { index: new_index, alias: config.read_alias } }
].compact
})
end

def stop_dual_writes
Rails.logger.info('Stopping dual writes - making index read and write aliases the same')
logger.info('Stopping dual writes - making index read and write aliases the same')
current_index = config.client.indices.get_alias(name: config.read_alias).keys.first

Rails.logger.info("Currently used index is #{current_index}")
logger.info("Currently used index is #{current_index}")

other_write_indices = config.client.indices.get_alias(name: config.write_alias).keys
.reject { |name| name == current_index }
.reject { |name| name == current_index }

if other_write_indices.none?
Rails.logger.info("No write indexes that aren't the read index. Nothing to do!")
logger.info("No write indexes that aren't the read index. Nothing to do!")
return
end
Rails.logger.info("Stopping writes to #{other_write_indices.count} old ES indices: " \
logger.info("Stopping writes to #{other_write_indices.count} old ES indices: " \
"#{other_write_indices.join(', ')}")

actions = other_write_indices.map do |index|
Expand All @@ -59,36 +69,33 @@ def stop_dual_writes
end

def cleanup_old_indices
Rails.logger.info('Cleaning up old indices in Elasticsearch')
logger.info('Cleaning up old indices in Elasticsearch')
current_index = config.client.indices.get_alias(name: config.read_alias).keys.first

Rails.logger.info("Currently used index is #{current_index}")
logger.info("Currently used index is #{current_index}")

indices_to_delete = config.client
.cat
.indices(format: :json)
.map { |index| index['index'] }
.select { |name| name.start_with?(config.read_alias) }
.reject { |name| name == current_index }
.cat
.indices(format: :json)
.map { |index| index['index'] }
.select { |name| name.start_with?(config.read_alias) }
.reject { |name| name == current_index }

if indices_to_delete.none?
Rails.logger.info('Nothing to do: no old indices')
logger.info('Nothing to do: no old indices')
return
end
Rails.logger.info("Deleting #{indices_to_delete.count} old indices: #{indices_to_delete.join(', ')}")
logger.info("Deleting #{indices_to_delete.count} old indices: #{indices_to_delete.join(', ')}")
config.client.indices.delete(index: indices_to_delete)
end

def populate_index(unique_name = nil, batch_size: 3000)
index_name = if unique_name
[config.read_alias, unique_name].join('_')
else
config.write_alias
end
private

config.data_source.find_in_batches(batch_size: batch_size) do |batch|
index_batch(batch, index_name: index_name)
end
attr_reader :config
delegate :logger, to: :config

def indexer
@indexer ||= Indexer.new(config)
end
end
end
5 changes: 3 additions & 2 deletions lib/es_index/indexer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def delete_by_id(id)
end

def delete_by_ids(ids)
Rails.logger.info('ES: Deleting batch records')
logger.info('ES: Deleting batch records')

indices = config.client.indices.get_alias(name: config.write_alias).keys
commands = []
Expand All @@ -86,14 +86,15 @@ def delete_by_ids(ids)
end

def delete_by_query(query)
Rails.logger.info('ES: Deleting batch records')
logger.info('ES: Deleting batch records')

config.client.delete_by_query(index: config.write_alias, body: { query: query })
end

private

attr_reader :config
delegate :logger, to: :config

def current_version
config.data_source.connection.select_one('SELECT txid_current()').fetch('txid_current')
Expand Down
2 changes: 1 addition & 1 deletion lib/es_index/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module EsIndex
VERSION = "0.1.0"
VERSION = '0.1.0'.freeze
end
4 changes: 2 additions & 2 deletions spec/es_index_spec.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
RSpec.describe EsIndex do
it "has a version number" do
it 'has a version number' do
expect(EsIndex::VERSION).not_to be nil
end

it "does something useful" do
it 'does something useful' do
expect(false).to eq(true)
end
end
6 changes: 3 additions & 3 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
require "bundler/setup"
require "es_index"
require 'bundler/setup'
require 'es_index'

RSpec.configure do |config|
config.example_status_persistence_file_path = ".rspec_status"
config.example_status_persistence_file_path = '.rspec_status'

config.disable_monkey_patching!

Expand Down

0 comments on commit e352e87

Please sign in to comment.