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 ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in heliosphere.gemspec
4
+ gemspec
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
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -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,8 @@
1
+ Description:
2
+ Creates initializer stub
3
+
4
+ Example:
5
+ rails generate heliosphere
6
+
7
+ This will create:
8
+ config/initializers/heliosphere.rb
@@ -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,7 @@
1
+ Heliosphere.indexer.define do
2
+
3
+ # index Widget do
4
+ # text :name
5
+ # end
6
+
7
+ 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
@@ -0,0 +1,3 @@
1
+ module Heliosphere
2
+ VERSION = "0.0.1"
3
+ end
@@ -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: []