promiscuous 0.17.0 → 0.18.0

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/bin/promiscuous ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'promiscuous/cli'
4
+ begin
5
+ Promiscuous::CLI.new.run
6
+ rescue => e
7
+ $stderr.puts e.backtrace.join("\n")
8
+ $stderr.puts '-' * 80
9
+ $stderr.puts e.message
10
+ end
@@ -0,0 +1,159 @@
1
+ require 'promiscuous'
2
+
3
+ class Promiscuous::CLI
4
+ def replicate(config_options={}, &block)
5
+ require 'eventmachine'
6
+ require 'em-synchrony'
7
+
8
+ EM.synchrony do
9
+ trap_signals
10
+ Promiscuous::Loader.load_descriptors if defined?(Rails)
11
+ force_backend :rubyamqp
12
+ block.call
13
+ end
14
+ end
15
+
16
+ def force_backend(backend)
17
+ Promiscuous::AMQP.disconnect
18
+ Promiscuous::Config.backend = backend
19
+ Promiscuous::AMQP.connect
20
+ end
21
+
22
+ def trap_signals
23
+ %w(SIGTERM SIGINT).each do |signal|
24
+ Signal.trap(signal) do
25
+ print_status "Exiting..."
26
+ Promiscuous::Worker.stop
27
+ EM.stop
28
+ end
29
+ end
30
+ end
31
+
32
+ def publish(options={})
33
+ replicate do
34
+ Promiscuous::Worker.replicate(options)
35
+ print_status "Replicating with #{Promiscuous::Publisher::Mongoid::Defer.klasses.count} publishers"
36
+ end
37
+ end
38
+
39
+ def subscribe(options={})
40
+ replicate do
41
+ Promiscuous::Worker.replicate(options)
42
+ print_status "Replicating with #{Promiscuous::Subscriber::AMQP.subscribers.count} subscribers"
43
+ end
44
+ end
45
+
46
+ def publish_sync(options={})
47
+ print_status "Replicating #{options[:criteria]}..."
48
+ criteria = eval(options[:criteria])
49
+
50
+ bar = ProgressBar.create(:format => '%t |%b>%i| %c/%C %e', :title => 'Publishing', :total => criteria.count)
51
+ criteria.each do |doc|
52
+ doc.promiscuous_sync(options)
53
+ bar.increment
54
+ end
55
+
56
+ print_status "Done. You may switch your subscriber worker back to regular mode, and delete the sync queues"
57
+ end
58
+
59
+ def subscribe_sync(options={})
60
+ replicate do
61
+ # Create the regular queue if needed, so we don't lose messages.
62
+ Promiscuous::AMQP.open_queue(Promiscuous::Subscriber::Worker.new.queue_bindings)
63
+
64
+ print_status "WARNING: --- SYNC MODE ----"
65
+ print_status "WARNING: Make sure you are not running the regular subscriber worker (it's racy)"
66
+ print_status "WARNING: --- SYNC MODE ----"
67
+ Promiscuous::Worker.replicate(options)
68
+ print_status "Replicating with #{Promiscuous::Subscriber::AMQP.subscribers.count} subscribers"
69
+ end
70
+ end
71
+
72
+ def parse_args(args)
73
+ options = {}
74
+
75
+ parser = OptionParser.new do |opts|
76
+ opts.banner = "Usage: promiscuous [options] action"
77
+
78
+ opts.separator ""
79
+ opts.separator "Actions:"
80
+ opts.separator " publish"
81
+ opts.separator " subscribe"
82
+ opts.separator ""
83
+ opts.separator "Options:"
84
+
85
+ opts.on "-s", "--sync", "Use a separate queue for sychronizing databases" do
86
+ options[:personality] = :sync
87
+ end
88
+
89
+ opts.on "-c", "--criteria CRITERIA", "Published criteria in sync mode (often a model)" do |criteria|
90
+ options[:criteria] = criteria
91
+ end
92
+
93
+ opts.on "-b", "--bareback", "Bareback mode aka continue on error. Use with extreme caution" do
94
+ options[:bareback] = true
95
+ end
96
+
97
+ opts.on "-r", "--require FILE", "File to require to load your app. Don't worry about it with rails" do |file|
98
+ options[:require] = file
99
+ end
100
+
101
+ opts.on("-h", "--help", "Show this message") do
102
+ puts opts
103
+ exit
104
+ end
105
+
106
+ opts.on("-V", "--version", "Show version") do
107
+ puts "Promiscuous #{Promiscuous::VERSION}"
108
+ puts "License MIT"
109
+ exit
110
+ end
111
+ end
112
+
113
+ args = args.dup
114
+ parser.parse!(args)
115
+
116
+ options[:action] = args.shift.try(:to_sym)
117
+ raise "Please specify an action (publish or subscribe)" unless options[:action].in? [:publish, :subscribe]
118
+
119
+ if options[:action] == :publish && options[:personality] == :sync
120
+ raise "Please specify a criteria" unless options[:criteria]
121
+ else
122
+ raise "Why are you specifying a criteria?" if options[:criteria]
123
+ end
124
+
125
+ options
126
+ end
127
+
128
+ def load_app(options={})
129
+ if options[:require]
130
+ require options[:require]
131
+ else
132
+ require 'rails'
133
+ require File.expand_path("./config/environment.rb")
134
+ ::Rails.application.eager_load!
135
+ end
136
+ end
137
+
138
+ def run
139
+ options = parse_args(ARGV)
140
+ load_app(options)
141
+ maybe_warn_bareback(options)
142
+
143
+ # calls publish, publish_sync, subscribe, subscribe_sync
144
+ __send__([options[:action], options[:personality]].compact.join('_'), options)
145
+ end
146
+
147
+ def maybe_warn_bareback(options)
148
+ if options[:bareback]
149
+ print_status "WARNING: --- BAREBACK MODE ----"
150
+ print_status "WARNING: You are replicating without protection, you can get corrupted in no time"
151
+ print_status "WARNING: --- BAREBACK MODE ----"
152
+ end
153
+ end
154
+
155
+ def print_status(msg)
156
+ Promiscuous.info msg
157
+ $stderr.puts msg
158
+ end
159
+ end
@@ -15,7 +15,7 @@ module Promiscuous::Common::Worker
15
15
  end
16
16
 
17
17
  def bareback?
18
- !!ENV['BAREBACK']
18
+ !!options[:bareback]
19
19
  end
20
20
 
21
21
  included { attr_accessor :stop, :options }
@@ -1,7 +1,5 @@
1
1
  module Promiscuous
2
2
  class Railtie < Rails::Railtie
3
- rake_tasks { load 'promiscuous/railtie/replicate.rake' }
4
-
5
3
  initializer 'load promiscuous' do
6
4
  config.after_initialize do
7
5
  Promiscuous::Loader.load_descriptors(:publishers)
@@ -6,7 +6,7 @@ module Promiscuous::Subscriber::Mongoid::Versioning
6
6
 
7
7
  def atomic_selector
8
8
  if use_atomic_promiscuous_selector
9
- super.merge({ '$or' => [{'_psv' => { '$lt' => self._psv }},
9
+ super.merge({ '$or' => [{'_psv' => { '$lte' => self._psv }},
10
10
  {'_psv' => { '$exists' => false }}]})
11
11
  else
12
12
  super
@@ -1,3 +1,3 @@
1
1
  module Promiscuous
2
- VERSION = '0.17.0'
2
+ VERSION = '0.18.0'
3
3
  end
@@ -3,11 +3,11 @@ module Promiscuous::Worker
3
3
  self.workers = []
4
4
 
5
5
  def self.replicate(options={})
6
- publish = options[:only].nil? || options[:only] == :publish
7
- subscribe = options[:only].nil? || options[:only] == :subscribe
6
+ options[:action] ||= [:publish, :subscribe]
7
+ actions = [options[:action]].flatten
8
8
 
9
- self.workers << Promiscuous::Publisher::Worker.new(options) if publish
10
- self.workers << Promiscuous::Subscriber::Worker.new(options) if subscribe
9
+ self.workers << Promiscuous::Publisher::Worker.new(options) if :publish.in? actions
10
+ self.workers << Promiscuous::Subscriber::Worker.new(options) if :subscribe.in? actions
11
11
  self.workers.each { |w| w.replicate }
12
12
  end
13
13
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: promiscuous
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.17.0
4
+ version: 0.18.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2012-12-12 00:00:00.000000000 Z
13
+ date: 2012-12-19 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport
@@ -112,13 +112,14 @@ description: Replicate your Mongoid/ActiveRecord models across your applications
112
112
  email:
113
113
  - nicolas@viennot.biz
114
114
  - kareem@doubleonemedia.com
115
- executables: []
115
+ executables:
116
+ - promiscuous
116
117
  extensions: []
117
118
  extra_rdoc_files: []
118
119
  files:
119
120
  - lib/promiscuous/amqp/null.rb
120
- - lib/promiscuous/amqp/bunny.rb
121
121
  - lib/promiscuous/amqp/rubyamqp.rb
122
+ - lib/promiscuous/amqp/bunny.rb
122
123
  - lib/promiscuous/common/lint.rb
123
124
  - lib/promiscuous/common/lint/base.rb
124
125
  - lib/promiscuous/common/class_helpers.rb
@@ -148,8 +149,6 @@ files:
148
149
  - lib/promiscuous/publisher/ephemeral.rb
149
150
  - lib/promiscuous/publisher/mongoid.rb
150
151
  - lib/promiscuous/publisher/worker.rb
151
- - lib/promiscuous/railtie.rb
152
- - lib/promiscuous/railtie/replicate.rake
153
152
  - lib/promiscuous/subscriber/active_record.rb
154
153
  - lib/promiscuous/subscriber/envelope.rb
155
154
  - lib/promiscuous/subscriber/error.rb
@@ -176,12 +175,15 @@ files:
176
175
  - lib/promiscuous/common.rb
177
176
  - lib/promiscuous/config.rb
178
177
  - lib/promiscuous/amqp.rb
179
- - lib/promiscuous/worker.rb
180
178
  - lib/promiscuous/ephemeral.rb
181
179
  - lib/promiscuous/subscriber.rb
182
180
  - lib/promiscuous/publisher.rb
181
+ - lib/promiscuous/cli.rb
182
+ - lib/promiscuous/railtie.rb
183
+ - lib/promiscuous/worker.rb
183
184
  - lib/promiscuous/version.rb
184
185
  - lib/promiscuous.rb
186
+ - bin/promiscuous
185
187
  - README.md
186
188
  homepage: http://github.com/crowdtap/promiscuous
187
189
  licenses: []
@@ -1,87 +0,0 @@
1
- namespace :promiscuous do
2
- # Note These rake tasks can be loaded without Rails
3
-
4
- def trap_signals
5
- %w(SIGTERM SIGINT).each do |signal|
6
- Signal.trap(signal) do
7
- Promiscuous.info "Exiting..."
8
- Promiscuous::Worker.stop
9
- EM.stop
10
- end
11
- end
12
- end
13
-
14
- def print_status(msg)
15
- Promiscuous.info msg
16
- $stderr.puts msg
17
- end
18
-
19
- def force_backend(backend)
20
- Promiscuous::AMQP.disconnect
21
- Promiscuous::Config.backend = backend
22
- Promiscuous::AMQP.connect
23
- end
24
-
25
- def replicate(config_options={}, &block)
26
- require 'eventmachine'
27
- require 'em-synchrony'
28
-
29
- EM.synchrony do
30
- trap_signals
31
- Promiscuous::Loader.load_descriptors if defined?(Rails)
32
- force_backend :rubyamqp
33
- block.call
34
- end
35
- end
36
-
37
- desc 'Run the publisher worker'
38
- task :publish => :environment do
39
- replicate do
40
- Promiscuous::Worker.replicate :only => :publish
41
- print_status "Replicating with #{Promiscuous::Publisher::Mongoid::Defer.klasses.count} publishers"
42
- end
43
- end
44
-
45
- desc 'Run the subscriber worker'
46
- task :subscribe => :environment do
47
- replicate do
48
- Promiscuous::Worker.replicate :only => :subscribe
49
- print_status "Replicating with #{Promiscuous::Subscriber::AMQP.subscribers.count} subscribers"
50
- end
51
- end
52
-
53
- namespace :synchronized do
54
- desc 'Synchronize a collection'
55
- task :publish, [:criteria] => :environment do |t, args|
56
- raise "Usage: rake promiscuous:synchronized:publish[Model]" unless args.criteria
57
-
58
- criteria = eval(args.criteria)
59
- count = criteria.count
60
- print_status "Replicating #{args.criteria}..."
61
-
62
- bar = ProgressBar.create(:format => '%t |%b>%i| %c/%C %e',
63
- :title => 'Publishing',
64
- :total => count)
65
- criteria.each do |doc|
66
- doc.promiscuous_sync :personality => :sync
67
- bar.increment
68
- end
69
-
70
- print_status "Done. You may switch your subscriber worker back to regular mode, and delete the sync queues"
71
- end
72
-
73
- desc 'Subscribe to a collection synchronization'
74
- task :subscribe => :environment do |t|
75
- replicate do
76
- # Create the regular queue if needed, so we don't lose messages.
77
- Promiscuous::AMQP.open_queue(Promiscuous::Subscriber::Worker.new.queue_bindings)
78
-
79
- print_status "WARNING: --- SYNC MODE ----"
80
- print_status "WARNING: Make sure you are not running the regular subscriber worker (it's racy)"
81
- print_status "WARNING: --- SYNC MODE ----"
82
- Promiscuous::Worker.replicate :personality => :sync, :only => :subscribe
83
- print_status "Replicating with #{Promiscuous::Subscriber::AMQP.subscribers.count} subscribers"
84
- end
85
- end
86
- end
87
- end