Class: ActsAsFerret::Remote::Server

Inherits:
Object
  • Object
show all
Includes:
UnixDaemon
Defined in:
lib/ferret_server.rb

Overview

This class acts as a drb server listening for indexing and search requests from models declared to ‘acts_as_ferret :remote => true’

Usage:

  • modify RAILS_ROOT/config/ferret_server.yml to suit your needs.

  • environments for which no section in the config file exists will use the index locally (good for unit tests/development mode)

  • run script/ferret_server to start the server:

script/ferret_server -e production start

  • to stop the server run

script/ferret_server -e production stop

Instance Method Summary collapse

Methods included from UnixDaemon

#ensure_stopped, #platform_daemon, #process_exists, #read_pid_file, #safefork, #stop, #write_pid_file

Constructor Details

#initializeServer

Returns a new instance of Server.



69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/ferret_server.rb', line 69

def initialize
  ActiveRecord::Base.allow_concurrency = true
  require 'ar_mysql_auto_reconnect_patch'
  @cfg = ActsAsFerret::Remote::Config.new
  ActiveRecord::Base.logger = @logger = Logger.new(@cfg.log_file)
  ActiveRecord::Base.logger.level = Logger.const_get(@cfg.log_level.upcase) rescue Logger::DEBUG
  if @cfg.script
    path = File.join(RAILS_ROOT, @cfg.script) 
    load path
    @logger.info "loaded custom startup script from #{path}"
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args) ⇒ Object

handles all incoming method calls, and sends them on to the correct local index instance.

Calls are not queued, so this will block until the call returned.



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/ferret_server.rb', line 112

def method_missing(name, *args)
  @logger.debug "\#method_missing(#{name.inspect}, #{args.inspect})"


  index_name = args.shift
  index = if name.to_s =~ /^multi_(.+)/
    name = $1
    ActsAsFerret::multi_index(index_name)
  else
    ActsAsFerret::get_index(index_name)
  end

  if index.nil?
    @logger.error "\#index with name #{index_name} not found in call to #{name} with args #{args.inspect}"
    raise ActsAsFerret::IndexNotDefined.new(index_name)
  end


  # TODO find another way to implement the reconnection logic (maybe in
  # local_index or class_methods)
  #  reconnect_when_needed(clazz) do
  
  # using respond_to? here so we not have to catch NoMethodError
  # which would silently catch those from deep inside the indexing
  # code, too...

  if index.respond_to?(name)
    index.send name, *args
  # TODO check where we need this:
  #elsif clazz.respond_to?(name)
  #      @logger.debug "no luck, trying to call class method instead"
  #      clazz.send name, *args
  else
    raise NoMethodError.new("method #{name} not supported by DRb server")
  end
rescue => e
  @logger.error "ferret server error #{$!}\n#{$!.backtrace.join "\n"}"
  raise e
end

Instance Method Details

#db_disconnect!(class_name) ⇒ Object

disconnects the db connection for the class specified by class_name used only in unit tests to check the automatic reconnection feature



171
172
173
174
175
# File 'lib/ferret_server.rb', line 171

def db_disconnect!(class_name)
  with_class class_name do |clazz|
    clazz.connection.disconnect!
  end
end

#ensure_index_exists(index_name) ⇒ Object

make sure we have a versioned index in place, building one if necessary



160
161
162
163
164
165
166
167
# File 'lib/ferret_server.rb', line 160

def ensure_index_exists(index_name)
  @logger.debug "DRb server: ensure_index_exists for index #{index_name}"
  definition = ActsAsFerret::get_index(index_name).index_definition
  dir = definition[:index_dir]
  unless File.directory?(dir) && File.file?(File.join(dir, 'segments')) && dir =~ %r{/\d+(_\d+)?$}
    rebuild_index(index_name)
  end
end

#rebuild_index(index_name) ⇒ Object

hides LocalIndex#rebuild_index to implement index versioning



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/ferret_server.rb', line 178

def rebuild_index(index_name)
  definition = ActsAsFerret::get_index(index_name).index_definition.dup
  models = definition[:registered_models]
  index = new_index_for(definition)
  # TODO fix reconnection stuff
  #  reconnect_when_needed(clazz) do
  #    @logger.debug "DRb server: rebuild index for class(es) #{models.inspect} in #{index.options[:path]}"
  index.index_models models
  #  end
  new_version = File.join definition[:index_base_dir], Time.now.utc.strftime('%Y%m%d%H%M%S')
  # create a unique directory name (needed for unit tests where 
  # multiple rebuilds per second may occur)
  if File.exists?(new_version)
    i = 0
    i+=1 while File.exists?("#{new_version}_#{i}")
    new_version << "_#{i}"
  end
    
  File.rename index.options[:path], new_version
  ActsAsFerret::change_index_dir index_name, new_version 
end

#register_class(class_name) ⇒ Object



152
153
154
155
156
157
# File 'lib/ferret_server.rb', line 152

def register_class(class_name)
  @logger.debug "############ registerclass #{class_name}"
  class_name.constantize
  @logger.debug "index for class #{class_name}: #{ActsAsFerret::ferret_indexes[class_name.underscore.to_sym]}"

end

#runObject

run the server and block until it exits



91
92
93
94
# File 'lib/ferret_server.rb', line 91

def run
  raise "ferret_server not configured for #{RAILS_ENV}" unless (@cfg.uri rescue nil)
  run_drb_service
end

#run_drb_serviceObject



96
97
98
99
100
101
102
103
104
# File 'lib/ferret_server.rb', line 96

def run_drb_service
  $stdout.puts("starting ferret server...")
  self.class.running = true
  DRb.start_service(@cfg.uri, self)
  DRb.thread.join
rescue Exception => e
  @logger.error(e.to_s)
  raise
end

#startObject

start the server as a daemon process



84
85
86
87
# File 'lib/ferret_server.rb', line 84

def start
  raise "ferret_server not configured for #{RAILS_ENV}" unless (@cfg.uri rescue nil)
  platform_daemon { run_drb_service }
end