heliosphere 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/README.md +77 -0
- data/Rakefile +2 -0
- data/heliosphere.gemspec +21 -0
- data/lib/generators/USAGE +8 -0
- data/lib/generators/heliosphere_generator.rb +9 -0
- data/lib/generators/templates/heliosphere.rb +7 -0
- data/lib/heliosphere/config.rb +33 -0
- data/lib/heliosphere/indexer.rb +45 -0
- data/lib/heliosphere/observer.rb +39 -0
- data/lib/heliosphere/railtie.rb +22 -0
- data/lib/heliosphere/rspec.rb +21 -0
- data/lib/heliosphere/server.rb +52 -0
- data/lib/heliosphere/stubs.rb +36 -0
- data/lib/heliosphere/version.rb +3 -0
- data/lib/heliosphere.rb +35 -0
- data/lib/tasks/heliosphere.rake +30 -0
- metadata +66 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
# Heliosphere
|
2
|
+
|
3
|
+
The problem with Sunspot is that it doesn't check if Solr is really running. This means that you get
|
4
|
+
a nasty connection refused error whenever you save or destroy a record. We don't want that, the
|
5
|
+
search engine is usually less important than the feature that saves models.
|
6
|
+
|
7
|
+
Heliosphere tries to solve that, by making the commit hooks a bit safer. It will index if Solr is
|
8
|
+
available, but send a request to Hoptoad if its not there. You will manually have to reindex updated
|
9
|
+
and destroyed records.
|
10
|
+
|
11
|
+
The trick Heliosphere is doing is using the Unix tool `netstat` to check if Solr is really running
|
12
|
+
and excepting requests.
|
13
|
+
|
14
|
+
There are also some helpers for Rake, Cucumber and RSpec.
|
15
|
+
|
16
|
+
## Installation
|
17
|
+
|
18
|
+
The definition of the indexes go outside your model. Create a stub by running:
|
19
|
+
|
20
|
+
rails generate heliosphere
|
21
|
+
|
22
|
+
Modify the generated initializer to get it up and running.
|
23
|
+
|
24
|
+
|
25
|
+
## Testing Solr status by hand
|
26
|
+
|
27
|
+
Although saving records won't work now, you'll want to disable search forms or show a notice to the
|
28
|
+
user. To check manually if Solr is running:
|
29
|
+
|
30
|
+
Heliosphere.up?
|
31
|
+
# or ...
|
32
|
+
Heliosphere.down?
|
33
|
+
|
34
|
+
## Rake tasks
|
35
|
+
|
36
|
+
There are alternative Rake tasks for starting/stopping/reindexing safely. The rake tasks won't fire
|
37
|
+
up and forget, but wait until the server is really running. If Solr is already running, start won't
|
38
|
+
complain, if it isn't running than stop won't complain. This means that restart will always work, no
|
39
|
+
matter if solr is running or not.
|
40
|
+
|
41
|
+
Find them:
|
42
|
+
|
43
|
+
rake -T heliosphere
|
44
|
+
|
45
|
+
## Cucumber & RSpec
|
46
|
+
|
47
|
+
Add this for Cucumber:
|
48
|
+
|
49
|
+
Before("~@search") do
|
50
|
+
Heliosphere::Stubs.without_search
|
51
|
+
end
|
52
|
+
|
53
|
+
Before("@search") do
|
54
|
+
Heliosphere::Stubs.with_search
|
55
|
+
end
|
56
|
+
|
57
|
+
And this for RSpec:
|
58
|
+
|
59
|
+
RSpec.configure do |config|
|
60
|
+
config.extend Heliosphere::RSpec
|
61
|
+
end
|
62
|
+
|
63
|
+
Afterwards, use `with_search` and `without_search` inside describe blocks:
|
64
|
+
|
65
|
+
describe User do
|
66
|
+
without_search
|
67
|
+
it "will update records without indexing it in Solr"
|
68
|
+
end
|
69
|
+
|
70
|
+
## Todo
|
71
|
+
|
72
|
+
* Write tests
|
73
|
+
* Add Capistrano support
|
74
|
+
* Maybe forcefully stop Solr within testsuite
|
75
|
+
* Support other ways of notifying instead of just Hoptoad
|
76
|
+
|
77
|
+
Copyright (c) 2011 Iain Hecker, released under the MIT license
|
data/Rakefile
ADDED
data/heliosphere.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "heliosphere/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "heliosphere"
|
7
|
+
s.version = Heliosphere::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Iain Hecker"]
|
10
|
+
s.email = ["iain@iain.nl"]
|
11
|
+
s.homepage = "https://github.com/iain/heliosphere"
|
12
|
+
s.summary = %q{Heliosphere makes Sunspot less dangerous by allowing updates to occur when Solr isn't running.}
|
13
|
+
s.description = %q{Saving a record is usually more important than indexing it in Solr. Heliosphere will only index when Solr is running. It also includes some convenient rake tasks and a way to declare your indexes outside your model.}
|
14
|
+
|
15
|
+
s.rubyforge_project = "heliosphere"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class HeliosphereGenerator < Rails::Generators::Base
|
2
|
+
source_root File.expand_path('../templates', __FILE__)
|
3
|
+
|
4
|
+
desc "This generator creates an initializer file at config/initializers"
|
5
|
+
def create_initializer_file
|
6
|
+
copy_file "heliosphere.rb", "config/initializers/heliosphere.rb"
|
7
|
+
end
|
8
|
+
|
9
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Heliosphere
|
4
|
+
|
5
|
+
class Config
|
6
|
+
|
7
|
+
DEFAULT_CONFIG_FILE = 'config/sunspot.yml'
|
8
|
+
|
9
|
+
attr_reader :config_file
|
10
|
+
|
11
|
+
def initialize(config_file = nil)
|
12
|
+
@config_file = config_file || DEFAULT_CONFIG_FILE
|
13
|
+
end
|
14
|
+
|
15
|
+
def config
|
16
|
+
@config ||= YAML.load(File.read(config_file))
|
17
|
+
end
|
18
|
+
|
19
|
+
def port
|
20
|
+
@port ||= config[environment]['solr']['port']
|
21
|
+
end
|
22
|
+
|
23
|
+
def info
|
24
|
+
"Running in #{environment} environment on port #{port}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def environment
|
28
|
+
Rails.env.to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Heliosphere
|
2
|
+
|
3
|
+
def self.indexer
|
4
|
+
@indexer ||= Indexer.new
|
5
|
+
end
|
6
|
+
|
7
|
+
class Indexer
|
8
|
+
|
9
|
+
SEARCH_WITHOUT_LIFECYCLE = { :auto_index => false, :auto_remove => false }
|
10
|
+
|
11
|
+
attr_accessor :block
|
12
|
+
|
13
|
+
def define(&block)
|
14
|
+
instance_eval(&block)
|
15
|
+
apply
|
16
|
+
end
|
17
|
+
|
18
|
+
def model_names
|
19
|
+
models.map { |model| model.name.underscore.to_sym }
|
20
|
+
end
|
21
|
+
|
22
|
+
def apply
|
23
|
+
options = SEARCH_WITHOUT_LIFECYCLE
|
24
|
+
model_definitions.each do |model, block|
|
25
|
+
model.instance_eval do
|
26
|
+
searchable(options, &block)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def index(model, &block)
|
32
|
+
model_definitions[model] = block
|
33
|
+
end
|
34
|
+
|
35
|
+
def models
|
36
|
+
model_definitions.keys
|
37
|
+
end
|
38
|
+
|
39
|
+
def model_definitions
|
40
|
+
@model_definitions ||= {}
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'heliosphere/indexer'
|
2
|
+
|
3
|
+
module Heliosphere
|
4
|
+
|
5
|
+
class Observer < ActiveRecord::Observer
|
6
|
+
|
7
|
+
observe *Heliosphere.indexer.model_names
|
8
|
+
|
9
|
+
def after_save(object)
|
10
|
+
running? { Sunspot.index(object) }
|
11
|
+
end
|
12
|
+
|
13
|
+
def after_destroy(object)
|
14
|
+
running? { Sunspot.remove(object) }
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def running?
|
20
|
+
if Heliosphere.up?
|
21
|
+
yield
|
22
|
+
else
|
23
|
+
notify_hoptoad if hoptoad?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def notify_hoptoad
|
28
|
+
HoptoadNotifier.notify(SolrNotRunning.new, :hostname => `hostname`)
|
29
|
+
end
|
30
|
+
|
31
|
+
def hoptoad?
|
32
|
+
defined?(HoptoadNotifier)
|
33
|
+
end
|
34
|
+
|
35
|
+
class SolrNotRunning < Exception; end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'heliosphere/observer'
|
2
|
+
|
3
|
+
module Heliosphere
|
4
|
+
|
5
|
+
class Railtie < Rails::Railtie
|
6
|
+
|
7
|
+
initializer "heliosphere.add_observer" do |app|
|
8
|
+
ar = app.config.active_record
|
9
|
+
if ar.observers
|
10
|
+
ar.observers += [ Heliosphere::Observer ]
|
11
|
+
else
|
12
|
+
ar.observers = [ Heliosphere::Observer ]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
rake_tasks do
|
17
|
+
load File.expand_path("../../tasks/heliosphere.rake", __FILE__)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'heliosphere/stubs'
|
2
|
+
|
3
|
+
module Heliosphere
|
4
|
+
|
5
|
+
module RSpec
|
6
|
+
|
7
|
+
def without_search
|
8
|
+
before :all do
|
9
|
+
Stubs.without_search
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def with_search
|
14
|
+
before :all do
|
15
|
+
Stubs.with_search
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'heliosphere/indexer'
|
2
|
+
|
3
|
+
module Heliosphere
|
4
|
+
|
5
|
+
class Server
|
6
|
+
|
7
|
+
POLL_INTERVAL = 1
|
8
|
+
|
9
|
+
attr_reader :port
|
10
|
+
|
11
|
+
def initialize(port)
|
12
|
+
@port = port
|
13
|
+
end
|
14
|
+
|
15
|
+
def start
|
16
|
+
Sunspot::Rails::Server.new.start if down?
|
17
|
+
wait(&:up?)
|
18
|
+
sleep POLL_INTERVAL
|
19
|
+
end
|
20
|
+
|
21
|
+
def stop
|
22
|
+
Sunspot::Rails::Server.new.stop if up?
|
23
|
+
wait(&:down?)
|
24
|
+
end
|
25
|
+
|
26
|
+
def start_and_reindex
|
27
|
+
start
|
28
|
+
reindex
|
29
|
+
end
|
30
|
+
|
31
|
+
def reindex
|
32
|
+
Heliosphere.indexer.models.each do |model|
|
33
|
+
model.remove_all_from_index
|
34
|
+
model.index
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def up?
|
39
|
+
`netstat -an` =~ /\b#{port}\b/m
|
40
|
+
end
|
41
|
+
|
42
|
+
def down?
|
43
|
+
not up?
|
44
|
+
end
|
45
|
+
|
46
|
+
def wait(&block)
|
47
|
+
sleep POLL_INTERVAL until yield(self)
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Heliosphere
|
2
|
+
|
3
|
+
module Stubs
|
4
|
+
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def session
|
8
|
+
@session ||= Sunspot.session
|
9
|
+
end
|
10
|
+
|
11
|
+
def without_search
|
12
|
+
Sunspot.session = Sunspot::Rails::StubSessionProxy.new(session)
|
13
|
+
end
|
14
|
+
|
15
|
+
def with_search
|
16
|
+
unless Heliosphere.up?
|
17
|
+
sunspot = Sunspot::Rails::Server.new
|
18
|
+
pid = fork do
|
19
|
+
STDERR.reopen('/dev/null')
|
20
|
+
STDOUT.reopen('/dev/null')
|
21
|
+
sunspot.run
|
22
|
+
end
|
23
|
+
# shut down the Solr server
|
24
|
+
at_exit { Process.kill('TERM', pid); Heliosphere.wait(&:down?) }
|
25
|
+
# wait for solr to start
|
26
|
+
Heliosphere.wait(&:up?)
|
27
|
+
end
|
28
|
+
|
29
|
+
Sunspot.session = session
|
30
|
+
Sunspot.session.remove_all
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
end
|
data/lib/heliosphere.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'heliosphere/server'
|
2
|
+
require 'heliosphere/config'
|
3
|
+
require 'heliosphere/railtie' if defined?(Rails)
|
4
|
+
|
5
|
+
module Heliosphere
|
6
|
+
|
7
|
+
def self.start
|
8
|
+
server.start
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.stop
|
12
|
+
server.stop
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.reindex
|
16
|
+
server.start_and_reindex
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.wait(&block)
|
20
|
+
server.wait(&block)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.up?
|
24
|
+
server.up?
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.server
|
28
|
+
@server ||= Server.new(config.port)
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.config
|
32
|
+
@config ||= Config.new
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
namespace :heliosphere do
|
2
|
+
|
3
|
+
def run(command)
|
4
|
+
puts Heliosphere.config.info
|
5
|
+
puts "Executing #{command}"
|
6
|
+
start = Time.now
|
7
|
+
Heliosphere.send(command)
|
8
|
+
elapsed = Time.now - start
|
9
|
+
puts "Executed in %0.02f seconds" % elapsed
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "Start Solr, but don't raise an error if it's already running"
|
13
|
+
task :start => :environment do
|
14
|
+
run :start
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "Reindex Solr, starting it if needed"
|
18
|
+
task :reindex => :environment do
|
19
|
+
run :reindex
|
20
|
+
end
|
21
|
+
|
22
|
+
desc "Stop Solr, if running."
|
23
|
+
task :stop => :environment do
|
24
|
+
run :stop
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "Restart Solr safely"
|
28
|
+
task :restart => [ :stop, :start ]
|
29
|
+
|
30
|
+
end
|
metadata
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: heliosphere
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Iain Hecker
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-10-26 00:00:00.000000000Z
|
13
|
+
dependencies: []
|
14
|
+
description: Saving a record is usually more important than indexing it in Solr. Heliosphere
|
15
|
+
will only index when Solr is running. It also includes some convenient rake tasks
|
16
|
+
and a way to declare your indexes outside your model.
|
17
|
+
email:
|
18
|
+
- iain@iain.nl
|
19
|
+
executables: []
|
20
|
+
extensions: []
|
21
|
+
extra_rdoc_files: []
|
22
|
+
files:
|
23
|
+
- .gitignore
|
24
|
+
- Gemfile
|
25
|
+
- README.md
|
26
|
+
- Rakefile
|
27
|
+
- heliosphere.gemspec
|
28
|
+
- lib/generators/USAGE
|
29
|
+
- lib/generators/heliosphere_generator.rb
|
30
|
+
- lib/generators/templates/heliosphere.rb
|
31
|
+
- lib/heliosphere.rb
|
32
|
+
- lib/heliosphere/config.rb
|
33
|
+
- lib/heliosphere/indexer.rb
|
34
|
+
- lib/heliosphere/observer.rb
|
35
|
+
- lib/heliosphere/railtie.rb
|
36
|
+
- lib/heliosphere/rspec.rb
|
37
|
+
- lib/heliosphere/server.rb
|
38
|
+
- lib/heliosphere/stubs.rb
|
39
|
+
- lib/heliosphere/version.rb
|
40
|
+
- lib/tasks/heliosphere.rake
|
41
|
+
homepage: https://github.com/iain/heliosphere
|
42
|
+
licenses: []
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options: []
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
none: false
|
49
|
+
requirements:
|
50
|
+
- - ! '>='
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0'
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ! '>='
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '0'
|
59
|
+
requirements: []
|
60
|
+
rubyforge_project: heliosphere
|
61
|
+
rubygems_version: 1.8.10
|
62
|
+
signing_key:
|
63
|
+
specification_version: 3
|
64
|
+
summary: Heliosphere makes Sunspot less dangerous by allowing updates to occur when
|
65
|
+
Solr isn't running.
|
66
|
+
test_files: []
|