promiscuous 0.12.1 → 0.13.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/lib/promiscuous/amqp/bunny.rb +10 -6
- data/lib/promiscuous/amqp/null.rb +2 -2
- data/lib/promiscuous/amqp/rubyamqp.rb +14 -12
- data/lib/promiscuous/amqp.rb +3 -1
- data/lib/promiscuous/common/worker.rb +3 -2
- data/lib/promiscuous/publisher/amqp.rb +3 -1
- data/lib/promiscuous/publisher/model.rb +6 -1
- data/lib/promiscuous/publisher/worker.rb +1 -1
- data/lib/promiscuous/railtie/replicate.rake +69 -20
- data/lib/promiscuous/subscriber/worker.rb +27 -19
- data/lib/promiscuous/version.rb +1 -1
- data/lib/promiscuous/worker.rb +6 -3
- metadata +24 -8
@@ -13,14 +13,18 @@ module Promiscuous
|
|
13
13
|
self.connection.stop
|
14
14
|
end
|
15
15
|
|
16
|
-
def self.publish(
|
17
|
-
Promiscuous.info "[publish] #{
|
18
|
-
exchange
|
19
|
-
|
16
|
+
def self.publish(options={})
|
17
|
+
Promiscuous.info "[publish] (#{options[:exchange_name]}) #{options[:key]} -> #{options[:payload]}"
|
18
|
+
exchange(options[:exchange_name]).
|
19
|
+
publish(options[:payload], :key => options[:key], :persistent => true)
|
20
20
|
end
|
21
21
|
|
22
|
-
def self.
|
23
|
-
raise "Cannot
|
22
|
+
def self.open_queue(options={}, &block)
|
23
|
+
raise "Cannot open queue with bunny"
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.exchange(name)
|
27
|
+
connection.exchange(name, :type => :topic, :durable => true)
|
24
28
|
end
|
25
29
|
end
|
26
30
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Promiscuous
|
2
2
|
module AMQP
|
3
3
|
module RubyAMQP
|
4
|
-
mattr_accessor :channel
|
4
|
+
mattr_accessor :channel
|
5
5
|
|
6
6
|
def self.connect
|
7
7
|
require 'amqp'
|
@@ -17,12 +17,11 @@ module Promiscuous
|
|
17
17
|
:user => uri.user,
|
18
18
|
:pass => uri.password,
|
19
19
|
:vhost => uri.path.empty? ? "/" : uri.path,
|
20
|
-
|
20
|
+
}
|
21
21
|
end
|
22
22
|
|
23
23
|
connection = ::AMQP.connect(amqp_options)
|
24
24
|
self.channel = ::AMQP::Channel.new(connection)
|
25
|
-
self.queue_options = Promiscuous::Config.queue_options
|
26
25
|
end
|
27
26
|
|
28
27
|
def self.disconnect
|
@@ -30,23 +29,26 @@ module Promiscuous
|
|
30
29
|
self.channel = nil
|
31
30
|
end
|
32
31
|
|
33
|
-
def self.
|
32
|
+
def self.open_queue(options={}, &block)
|
34
33
|
queue_name = options[:queue_name]
|
35
34
|
bindings = options[:bindings]
|
36
35
|
|
37
|
-
queue = self.channel.queue(queue_name,
|
38
|
-
exchange = channel.topic('promiscuous', :durable => true)
|
36
|
+
queue = self.channel.queue(queue_name, Promiscuous::Config.queue_options)
|
39
37
|
bindings.each do |binding|
|
40
|
-
queue.bind(exchange, :routing_key => binding)
|
38
|
+
queue.bind(exchange(options[:exchange_name]), :routing_key => binding)
|
41
39
|
Promiscuous.info "[bind] #{queue_name} -> #{binding}"
|
42
40
|
end
|
43
|
-
|
41
|
+
block.call(queue) if block
|
44
42
|
end
|
45
43
|
|
46
|
-
def self.publish(
|
47
|
-
Promiscuous.info "[publish] #{
|
48
|
-
exchange
|
49
|
-
|
44
|
+
def self.publish(options={})
|
45
|
+
Promiscuous.info "[publish] (#{options[:exchange_name]}) #{options[:key]} -> #{options[:payload]}"
|
46
|
+
exchange(options[:exchange_name]).
|
47
|
+
publish(options[:payload], :routing_key => options[:key], :persistent => true)
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.exchange(name)
|
51
|
+
channel.topic(name, :durable => true)
|
50
52
|
end
|
51
53
|
end
|
52
54
|
end
|
data/lib/promiscuous/amqp.rb
CHANGED
@@ -3,11 +3,13 @@ module Promiscuous::AMQP
|
|
3
3
|
autoload :RubyAMQP, 'promiscuous/amqp/rubyamqp'
|
4
4
|
autoload :Null, 'promiscuous/amqp/null'
|
5
5
|
|
6
|
+
EXCHANGE = 'promiscuous'.freeze
|
7
|
+
|
6
8
|
class << self
|
7
9
|
def backend
|
8
10
|
Promiscuous::Config.backend
|
9
11
|
end
|
10
12
|
|
11
|
-
delegate :connect, :disconnect, :publish, :
|
13
|
+
delegate :connect, :disconnect, :publish, :open_queue, :to => :backend
|
12
14
|
end
|
13
15
|
end
|
@@ -1,7 +1,8 @@
|
|
1
1
|
module Promiscuous::Common::Worker
|
2
2
|
extend ActiveSupport::Concern
|
3
3
|
|
4
|
-
def initialize
|
4
|
+
def initialize(options={})
|
5
|
+
self.options = options
|
5
6
|
self.stop = false
|
6
7
|
end
|
7
8
|
|
@@ -13,5 +14,5 @@ module Promiscuous::Common::Worker
|
|
13
14
|
end
|
14
15
|
end
|
15
16
|
|
16
|
-
included { attr_accessor :stop }
|
17
|
+
included { attr_accessor :stop, :options }
|
17
18
|
end
|
@@ -3,7 +3,9 @@ module Promiscuous::Publisher::AMQP
|
|
3
3
|
include Promiscuous::Publisher::Envelope
|
4
4
|
|
5
5
|
def publish
|
6
|
-
Promiscuous::AMQP
|
6
|
+
exchange_name = Promiscuous::AMQP::EXCHANGE
|
7
|
+
exchange_name += ".#{options[:personality]}" if options[:personality]
|
8
|
+
Promiscuous::AMQP.publish(:exchange_name => exchange_name, :key => to, :payload => payload.to_json)
|
7
9
|
end
|
8
10
|
|
9
11
|
def payload
|
@@ -36,7 +36,12 @@ module Promiscuous::Publisher::Model
|
|
36
36
|
self.class.promiscuous_publisher.new(:instance => self, :operation => operation).publish
|
37
37
|
end
|
38
38
|
end
|
39
|
-
|
39
|
+
|
40
|
+
def promiscuous_sync(options={})
|
41
|
+
options = options.merge({ :instance => self, :operation => :update, :defer => false })
|
42
|
+
self.class.promiscuous_publisher.new(options).publish
|
43
|
+
true
|
44
|
+
end
|
40
45
|
end
|
41
46
|
end
|
42
47
|
end
|
@@ -49,7 +49,7 @@ class Promiscuous::Publisher::Worker
|
|
49
49
|
|
50
50
|
def replicate_instance(instance)
|
51
51
|
return if self.stop
|
52
|
-
instance.
|
52
|
+
instance.promiscuous_sync
|
53
53
|
rescue Exception => e
|
54
54
|
# TODO set back the psp field
|
55
55
|
raise Promiscuous::Publisher::Error.new(e, instance)
|
@@ -1,24 +1,5 @@
|
|
1
1
|
namespace :promiscuous do
|
2
|
-
# Note
|
3
|
-
desc 'Run the workers'
|
4
|
-
task :replicate => :environment do |t|
|
5
|
-
require 'eventmachine'
|
6
|
-
require 'em-synchrony'
|
7
|
-
|
8
|
-
EM.synchrony do
|
9
|
-
trap_signals
|
10
|
-
force_backend :rubyamqp
|
11
|
-
|
12
|
-
Promiscuous::Loader.load_descriptors if defined?(Rails)
|
13
|
-
|
14
|
-
Promiscuous::Worker.replicate
|
15
|
-
|
16
|
-
msg = "Replicating with #{Promiscuous::Subscriber::AMQP.subscribers.count} subscribers" +
|
17
|
-
" and #{Promiscuous::Publisher::Mongoid::Defer.klasses.count} publishers"
|
18
|
-
Promiscuous.info msg
|
19
|
-
$stderr.puts msg
|
20
|
-
end
|
21
|
-
end
|
2
|
+
# Note These rake tasks can be loaded without Rails
|
22
3
|
|
23
4
|
def trap_signals
|
24
5
|
%w(SIGTERM SIGINT).each do |signal|
|
@@ -30,9 +11,77 @@ namespace :promiscuous do
|
|
30
11
|
end
|
31
12
|
end
|
32
13
|
|
14
|
+
def print_status(msg)
|
15
|
+
Promiscuous.info msg
|
16
|
+
$stderr.puts msg
|
17
|
+
end
|
18
|
+
|
33
19
|
def force_backend(backend)
|
34
20
|
Promiscuous::AMQP.disconnect
|
35
21
|
Promiscuous::Config.backend = backend
|
36
22
|
Promiscuous::AMQP.connect
|
37
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
|
38
87
|
end
|
@@ -2,31 +2,39 @@ class Promiscuous::Subscriber::Worker
|
|
2
2
|
include Promiscuous::Common::Worker
|
3
3
|
|
4
4
|
def replicate
|
5
|
-
Promiscuous::AMQP.
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
5
|
+
Promiscuous::AMQP.open_queue(queue_bindings) do |queue|
|
6
|
+
queue.subscribe :ack => true do |metadata, payload|
|
7
|
+
# Note: This code always runs on the root Fiber,
|
8
|
+
# so ordering is always preserved
|
9
|
+
begin
|
10
|
+
unless self.stop
|
11
|
+
Promiscuous.info "[receive] #{payload}"
|
12
|
+
self.unit_of_work { Promiscuous::Subscriber.process(JSON.parse(payload)) }
|
13
|
+
metadata.ack
|
14
|
+
end
|
15
|
+
rescue Exception => e
|
16
|
+
e = Promiscuous::Subscriber::Error.new(e, payload)
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
18
|
+
self.stop = true
|
19
|
+
Promiscuous::AMQP.disconnect
|
20
|
+
Promiscuous.error "[receive] FATAL #{e} #{e.backtrace.join("\n")}"
|
21
|
+
Promiscuous.error "[receive] FATAL #{e}"
|
22
|
+
Promiscuous::Config.error_handler.try(:call, e)
|
23
|
+
end
|
23
24
|
end
|
24
25
|
end
|
25
26
|
end
|
26
27
|
|
27
|
-
def
|
28
|
+
def queue_bindings
|
28
29
|
queue_name = "#{Promiscuous::Config.app}.promiscuous"
|
30
|
+
exchange_name = Promiscuous::AMQP::EXCHANGE
|
31
|
+
|
32
|
+
if options[:personality]
|
33
|
+
queue_name += ".#{options[:personality]}"
|
34
|
+
exchange_name += ".#{options[:personality]}"
|
35
|
+
end
|
36
|
+
|
29
37
|
bindings = Promiscuous::Subscriber::AMQP.subscribers.keys
|
30
|
-
{:queue_name => queue_name, :bindings => bindings}
|
38
|
+
{:exchange_name => exchange_name, :queue_name => queue_name, :bindings => bindings}
|
31
39
|
end
|
32
40
|
end
|
data/lib/promiscuous/version.rb
CHANGED
data/lib/promiscuous/worker.rb
CHANGED
@@ -2,9 +2,12 @@ module Promiscuous::Worker
|
|
2
2
|
mattr_accessor :workers
|
3
3
|
self.workers = []
|
4
4
|
|
5
|
-
def self.replicate
|
6
|
-
|
7
|
-
|
5
|
+
def self.replicate(options={})
|
6
|
+
publish = options[:only].nil? || options[:only] == :publish
|
7
|
+
subscribe = options[:only].nil? || options[:only] == :subscribe
|
8
|
+
|
9
|
+
self.workers << Promiscuous::Publisher::Worker.new(options) if publish
|
10
|
+
self.workers << Promiscuous::Subscriber::Worker.new(options) if subscribe
|
8
11
|
self.workers.each { |w| w.replicate }
|
9
12
|
end
|
10
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.
|
4
|
+
version: 0.13.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-11-
|
13
|
+
date: 2012-11-15 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activesupport
|
@@ -92,6 +92,22 @@ dependencies:
|
|
92
92
|
- - ! '>='
|
93
93
|
- !ruby/object:Gem::Version
|
94
94
|
version: '0'
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: ruby-progressbar
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
|
+
requirements:
|
100
|
+
- - ! '>='
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
type: :runtime
|
104
|
+
prerelease: false
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ! '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
95
111
|
description: Replicate your Mongoid/ActiveRecord models across your applications
|
96
112
|
email:
|
97
113
|
- nicolas@viennot.biz
|
@@ -101,7 +117,6 @@ extensions: []
|
|
101
117
|
extra_rdoc_files: []
|
102
118
|
files:
|
103
119
|
- lib/promiscuous.rb
|
104
|
-
- lib/promiscuous/amqp.rb
|
105
120
|
- lib/promiscuous/amqp/bunny.rb
|
106
121
|
- lib/promiscuous/amqp/null.rb
|
107
122
|
- lib/promiscuous/amqp/rubyamqp.rb
|
@@ -116,7 +131,6 @@ files:
|
|
116
131
|
- lib/promiscuous/observer.rb
|
117
132
|
- lib/promiscuous/publisher.rb
|
118
133
|
- lib/promiscuous/publisher/active_record.rb
|
119
|
-
- lib/promiscuous/publisher/amqp.rb
|
120
134
|
- lib/promiscuous/publisher/base.rb
|
121
135
|
- lib/promiscuous/publisher/class.rb
|
122
136
|
- lib/promiscuous/publisher/envelope.rb
|
@@ -129,15 +143,16 @@ files:
|
|
129
143
|
- lib/promiscuous/publisher/lint/class.rb
|
130
144
|
- lib/promiscuous/publisher/lint/polymorphic.rb
|
131
145
|
- lib/promiscuous/publisher/mock.rb
|
132
|
-
- lib/promiscuous/publisher/model.rb
|
133
146
|
- lib/promiscuous/publisher/mongoid/embedded.rb
|
134
147
|
- lib/promiscuous/publisher/mongoid/defer.rb
|
135
148
|
- lib/promiscuous/publisher/mongoid/defer_embedded.rb
|
136
149
|
- lib/promiscuous/publisher/mongoid/embedded_many.rb
|
137
150
|
- lib/promiscuous/publisher/polymorphic.rb
|
138
|
-
- lib/promiscuous/publisher/worker.rb
|
139
151
|
- lib/promiscuous/publisher/attributes.rb
|
140
152
|
- lib/promiscuous/publisher/mongoid.rb
|
153
|
+
- lib/promiscuous/publisher/amqp.rb
|
154
|
+
- lib/promiscuous/publisher/model.rb
|
155
|
+
- lib/promiscuous/publisher/worker.rb
|
141
156
|
- lib/promiscuous/railtie.rb
|
142
157
|
- lib/promiscuous/railtie/replicate.rake
|
143
158
|
- lib/promiscuous/subscriber/active_record.rb
|
@@ -156,14 +171,15 @@ files:
|
|
156
171
|
- lib/promiscuous/subscriber/observer.rb
|
157
172
|
- lib/promiscuous/subscriber/polymorphic.rb
|
158
173
|
- lib/promiscuous/subscriber/upsert.rb
|
159
|
-
- lib/promiscuous/subscriber/worker.rb
|
160
174
|
- lib/promiscuous/subscriber/amqp.rb
|
161
175
|
- lib/promiscuous/subscriber/attributes.rb
|
162
176
|
- lib/promiscuous/subscriber/base.rb
|
163
177
|
- lib/promiscuous/subscriber/mongoid.rb
|
164
|
-
- lib/promiscuous/worker.rb
|
178
|
+
- lib/promiscuous/subscriber/worker.rb
|
165
179
|
- lib/promiscuous/subscriber.rb
|
166
180
|
- lib/promiscuous/ephemeral.rb
|
181
|
+
- lib/promiscuous/amqp.rb
|
182
|
+
- lib/promiscuous/worker.rb
|
167
183
|
- lib/promiscuous/version.rb
|
168
184
|
- README.md
|
169
185
|
homepage: http://github.com/crowdtap/promiscuous
|