Class: ActsAsFerret::Server::Server

Inherits:
Object
  • Object
show all
Includes:
UnixDaemon
Defined in:
lib/acts_as_ferret/server/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.



29
30
31
32
33
34
35
36
37
38
# File 'lib/acts_as_ferret/server/server.rb', line 29

def initialize
  @cfg = 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.



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/acts_as_ferret/server/server.rb', line 67

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



126
127
128
129
130
# File 'lib/acts_as_ferret/server/server.rb', line 126

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



115
116
117
118
119
120
121
122
# File 'lib/acts_as_ferret/server/server.rb', line 115

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



133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/acts_as_ferret/server/server.rb', line 133

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



107
108
109
110
111
112
# File 'lib/acts_as_ferret/server/server.rb', line 107

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



47
48
49
50
# File 'lib/acts_as_ferret/server/server.rb', line 47

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

#run_drb_serviceObject



52
53
54
55
56
57
58
59
60
# File 'lib/acts_as_ferret/server/server.rb', line 52

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



41
42
43
44
# File 'lib/acts_as_ferret/server/server.rb', line 41

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