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

#platform_daemon, #read_pid_file, #safefork, #stop, #write_pid_file

Constructor Details

#initializeServer

Returns a new instance of Server.



64
65
66
67
68
69
# File 'lib/ferret_server.rb', line 64

def initialize
  @cfg = ActsAsFerret::Remote::Config.new
  ActiveRecord::Base.allow_concurrency = true
  ActiveRecord::Base.logger = @logger = Logger.new(@cfg.log_file)
  ActiveRecord::Base.logger.level = Logger.const_get(@cfg.log_level.upcase) rescue Logger::DEBUG
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 LocalIndex instance of the correct model class.

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



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/ferret_server.rb', line 93

def method_missing(name, *args)
  @logger.debug "\#method_missing(#{name.inspect}, #{args.inspect})"
  retried = false
  with_class args.shift do |clazz|
    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 clazz.aaf_index.respond_to?(name)
        clazz.aaf_index.send name, *args
      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
    end
  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



129
130
131
132
133
# File 'lib/ferret_server.rb', line 129

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

#ensure_index_exists(class_name) ⇒ Object

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



117
118
119
120
121
122
123
124
125
# File 'lib/ferret_server.rb', line 117

def ensure_index_exists(class_name)
  @logger.debug "DRb server: ensure_index_exists for class #{class_name}"
  with_class class_name do |clazz|
    dir = clazz.aaf_configuration[:index_dir]
    unless File.directory?(dir) && File.file?(File.join(dir, 'segments')) && dir =~ %r{/\d+(_\d+)?$}
      rebuild_index(clazz)
    end
  end
end

#rebuild_index(clazz, *models) ⇒ Object

hides LocalIndex#rebuild_index to implement index versioning



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/ferret_server.rb', line 136

def rebuild_index(clazz, *models)
  with_class clazz do |clazz|
    models = models.flatten.uniq.map(&:constantize)
    models << clazz unless models.include?(clazz)
    index = new_index_for(clazz, models)
    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 clazz.aaf_configuration[: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
    clazz.index_dir = new_version 
  end
end

#startObject

start the server



73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/ferret_server.rb', line 73

def start
  raise "ferret_server not configured for #{RAILS_ENV}" unless (@cfg.uri rescue nil)
  $stdout.puts("starting ferret server...")

  platform_daemon do 
    self.class.running = true
    DRb.start_service(@cfg.uri, self)
    DRb.thread.join
  end
rescue Exception => e
  @logger.error(e.to_s)
  raise
end