heliosphere 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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: []
|