promiscuous 0.9.3.1 → 0.10
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/README.md +16 -113
- data/lib/promiscuous/amqp/rubyamqp.rb +7 -6
- data/lib/promiscuous/common/worker.rb +17 -0
- data/lib/promiscuous/common.rb +1 -0
- data/lib/promiscuous/publisher/amqp.rb +1 -1
- data/lib/promiscuous/publisher/error.rb +18 -0
- data/lib/promiscuous/publisher/model.rb +1 -1
- data/lib/promiscuous/publisher/mongoid/defer.rb +52 -0
- data/lib/promiscuous/publisher/mongoid.rb +6 -0
- data/lib/promiscuous/publisher/worker.rb +49 -0
- data/lib/promiscuous/publisher.rb +2 -0
- data/lib/promiscuous/railtie/replicate.rake +27 -7
- data/lib/promiscuous/subscriber/amqp.rb +1 -1
- data/lib/promiscuous/subscriber/mongoid/embedded.rb +1 -1
- data/lib/promiscuous/subscriber/polymorphic.rb +0 -1
- data/lib/promiscuous/subscriber/worker.rb +31 -0
- data/lib/promiscuous/subscriber.rb +1 -0
- data/lib/promiscuous/version.rb +1 -1
- data/lib/promiscuous/worker.rb +12 -48
- data/lib/promiscuous.rb +1 -0
- metadata +16 -11
data/README.md
CHANGED
@@ -3,119 +3,22 @@ Promiscuous
|
|
3
3
|
|
4
4
|
[](https://secure.travis-ci.org/crowdtap/promiscuous)
|
5
5
|
|
6
|
-
Promiscuous
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
### In your publisher app
|
23
|
-
|
24
|
-
```ruby
|
25
|
-
# initializer
|
26
|
-
Promiscuous::AMQP.configure(:app => 'crowdtap',
|
27
|
-
:server_uri => 'amqp://user:password@host:port/vhost')
|
28
|
-
|
29
|
-
# publisher
|
30
|
-
class ModelPublisher < Promiscuous::Publisher::Mongoid
|
31
|
-
publish :to => 'crowdtap/model',
|
32
|
-
:class => :Model,
|
33
|
-
:attributes => [:field_1, :field_2, :field_3]
|
34
|
-
end
|
35
|
-
```
|
36
|
-
|
37
|
-
### In your subscriber app
|
38
|
-
|
39
|
-
```ruby
|
40
|
-
# initializer
|
41
|
-
Promiscuous::AMQP.configure(:app => 'sniper',
|
42
|
-
:server_uri => 'amqp://user:password@host:port/vhost',
|
43
|
-
:error_handler => some_proc)
|
44
|
-
|
45
|
-
# subscriber
|
46
|
-
class ModelSubscriber < Promiscuous::Subscriber::Mongoid
|
47
|
-
subscribe :from => 'crowdtap/model',
|
48
|
-
:attributes => [:field_1, :field_2, :field_3],
|
49
|
-
:class => Model, # optional
|
50
|
-
:foreign_key => :publisher_id # optional
|
51
|
-
end
|
52
|
-
```
|
53
|
-
|
54
|
-
### Starting the subscriber worker
|
55
|
-
|
56
|
-
rake promiscuous:replicate
|
57
|
-
|
58
|
-
How does it work ?
|
59
|
-
------------------
|
60
|
-
|
61
|
-
1. On the publisher side, Promiscuous hooks into the after_create/update/destroy callbacks.
|
62
|
-
2. When a model changes, Promiscuous sends a message to RabbitMQ, to the
|
63
|
-
'promiscuous' [topic exchange](http://www.rabbitmq.com/tutorials/tutorial-five-python.html).
|
64
|
-
3. RabbitMQ routes the messages to each application through queues.
|
65
|
-
We use one queue per application (TODO explain why we need one queue).
|
66
|
-
4. Subscribers apps are running the promiscuous worker, listening on their own queues,
|
67
|
-
executing the create/update/destroy on their databases.
|
68
|
-
|
69
|
-
Note that we use a single exchange to preserve the ordering of data updates
|
70
|
-
across application so that subscribers always see a consistant state of the
|
71
|
-
system.
|
72
|
-
|
73
|
-
Synching databases
|
74
|
-
-------------------
|
75
|
-
|
76
|
-
Documents are created if not present when receiving an update on a non existing
|
77
|
-
document.
|
78
|
-
|
79
|
-
TODO: Explain how to sync databases.
|
80
|
-
|
81
|
-
WARNING/TODO
|
82
|
-
------------
|
83
|
-
|
84
|
-
Promiscuous does **not** handle:
|
85
|
-
- ActiveRecord polymorphism.
|
86
|
-
- Any of the Mongoid atomic operatiors, such as inc, or add_to_set.
|
87
|
-
- Association magic. Example:
|
88
|
-
```ruby
|
89
|
-
# This will NOT replicate particiation_ids:
|
90
|
-
m = Member.first
|
91
|
-
m.particiations = [Participation.first]
|
92
|
-
m.save
|
93
|
-
|
94
|
-
# On the other hand, this will:
|
95
|
-
m = Member.first
|
96
|
-
m.particiation_ids = [Participation.first.ids]
|
97
|
-
m.save
|
98
|
-
```
|
99
|
-
|
100
|
-
Furthermore, it can be racy. Consider this scenario with two interleaving
|
101
|
-
requests A and B:
|
102
|
-
|
103
|
-
1. (A) Update mongo doc X.value = 1
|
104
|
-
2. (B) Update mongo doc X.value = 2
|
105
|
-
3. (B) Publish 'X.value = 2' to Rabbit
|
106
|
-
4. (A) Publish 'X.value = 1' to Rabbit
|
107
|
-
|
108
|
-
At the end of the scenario, on the publisher side, the document X has value
|
109
|
-
equal to 2, while on the subscriber side, the document has a value of 1. This
|
110
|
-
will likely not occur in most scenarios BUT BEWARE. We have plans to fix this
|
111
|
-
issue by using version numbers and mongo's amazing findandmodify.
|
112
|
-
|
113
|
-
Backend: bunny / ruby-amqp
|
114
|
-
--------------------------
|
115
|
-
|
116
|
-
Your publisher app may not run an eventmachine loop, which is required for
|
117
|
-
ruby-amqp. Bunny on the other hand allows a non-eventmachine based application
|
118
|
-
to publish messages to rabbitmq.
|
6
|
+
Promiscuous is designed to facilitate designing a
|
7
|
+
[service-oriented architecture](http://en.wikipedia.org/wiki/Service-oriented_architecture)
|
8
|
+
in Ruby.
|
9
|
+
|
10
|
+
Promiscuous offers an automatic way of propagating your data across one or more
|
11
|
+
applications. It supports Mongoid2, Mongoid3 and ActiveRecord.
|
12
|
+
It relies on [RabbitMQ](http://www.rabbitmq.com/) to push data around.
|
13
|
+
|
14
|
+
Philosophy
|
15
|
+
----------
|
16
|
+
|
17
|
+
In order for a service-oriented system to be successful, services *must* be
|
18
|
+
loosely coupled. The traditional Ruby way of tackling this problem is to
|
19
|
+
provide RESTful APIs.
|
20
|
+
Sadly, this come to a cost since one must write controllers, integration tests, etc.
|
21
|
+
Promiscuous to the rescue
|
119
22
|
|
120
23
|
Compatibility
|
121
24
|
-------------
|
@@ -11,12 +11,12 @@ module Promiscuous
|
|
11
11
|
raise "Please use amqp://user:password@host:port/vhost" if uri.scheme != 'amqp'
|
12
12
|
|
13
13
|
{
|
14
|
-
:host
|
15
|
-
:port
|
14
|
+
:host => uri.host,
|
15
|
+
:port => uri.port,
|
16
16
|
:scheme => uri.scheme,
|
17
|
-
:user
|
18
|
-
:pass
|
19
|
-
:vhost
|
17
|
+
:user => uri.user,
|
18
|
+
:pass => uri.password,
|
19
|
+
:vhost => uri.path.empty? ? "/" : uri.path,
|
20
20
|
}
|
21
21
|
end
|
22
22
|
|
@@ -26,7 +26,8 @@ module Promiscuous
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def self.disconnect
|
29
|
-
channel.close
|
29
|
+
self.channel.close if self.channel
|
30
|
+
self.channel = nil
|
30
31
|
end
|
31
32
|
|
32
33
|
def self.subscribe(options={}, &block)
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Promiscuous::Common::Worker
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
self.stop = false
|
6
|
+
end
|
7
|
+
|
8
|
+
def unit_of_work
|
9
|
+
if defined?(Mongoid)
|
10
|
+
Mongoid.unit_of_work { yield }
|
11
|
+
else
|
12
|
+
yield
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
included { attr_accessor :stop }
|
17
|
+
end
|
data/lib/promiscuous/common.rb
CHANGED
@@ -0,0 +1,18 @@
|
|
1
|
+
class Promiscuous::Publisher::Error < RuntimeError
|
2
|
+
attr_accessor :inner, :instance
|
3
|
+
|
4
|
+
def initialize(inner, instance)
|
5
|
+
super(inner)
|
6
|
+
set_backtrace(inner.backtrace)
|
7
|
+
self.inner = inner
|
8
|
+
self.instance = instance
|
9
|
+
end
|
10
|
+
|
11
|
+
def message
|
12
|
+
"#{inner.message} while processing #{instance}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
message
|
17
|
+
end
|
18
|
+
end
|
@@ -33,7 +33,7 @@ module Promiscuous::Publisher::Model
|
|
33
33
|
[:create, :update, :destroy].each do |operation|
|
34
34
|
__send__("after_#{operation}", "promiscuous_publish_#{operation}".to_sym)
|
35
35
|
define_method "promiscuous_publish_#{operation}" do
|
36
|
-
self.class.promiscuous_publisher.new(:instance => self, :operation => operation).
|
36
|
+
self.class.promiscuous_publisher.new(:instance => self, :operation => operation).publish
|
37
37
|
end
|
38
38
|
end
|
39
39
|
alias :promiscuous_sync :promiscuous_publish_update
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Promiscuous::Publisher::Mongoid::Defer
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
mattr_accessor :klasses
|
5
|
+
self.klasses = {}
|
6
|
+
|
7
|
+
def publish
|
8
|
+
super unless should_defer?
|
9
|
+
end
|
10
|
+
|
11
|
+
def should_defer?
|
12
|
+
if options.has_key?(:defer)
|
13
|
+
options[:defer]
|
14
|
+
else
|
15
|
+
operation == :update
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.hook_mongoid
|
20
|
+
return if @mongoid_hooked
|
21
|
+
@mongoid_hooked = true
|
22
|
+
|
23
|
+
Moped::Query.class_eval do
|
24
|
+
alias_method :update_orig, :update
|
25
|
+
def update(change, flags = nil)
|
26
|
+
if klass = Promiscuous::Publisher::Mongoid::Defer.klasses[@collection.name]
|
27
|
+
psp_field = klass.aliased_fields["promiscous_sync_pending"]
|
28
|
+
change = change.dup
|
29
|
+
change['$set'] ||= {}
|
30
|
+
change['$set'].merge!(psp_field => true)
|
31
|
+
end
|
32
|
+
update_orig(change, flags)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
included do
|
38
|
+
klass.class_eval do
|
39
|
+
cattr_accessor :publisher_defer_hooked
|
40
|
+
return if self.publisher_defer_hooked
|
41
|
+
self.publisher_defer_hooked = true
|
42
|
+
|
43
|
+
# TODO Make sure we are not overriding a field, although VERY unlikly
|
44
|
+
psp_field = :_psp
|
45
|
+
field psp_field, :as => :promiscous_sync_pending, :type => Boolean
|
46
|
+
index({psp_field => 1}, :background => true, :sparse => true)
|
47
|
+
|
48
|
+
Promiscuous::Publisher::Mongoid::Defer.hook_mongoid
|
49
|
+
Promiscuous::Publisher::Mongoid::Defer.klasses[collection.name] = self
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
class Promiscuous::Publisher::Mongoid < Promiscuous::Publisher::Base
|
2
2
|
autoload :Embedded, 'promiscuous/publisher/mongoid/embedded'
|
3
|
+
autoload :Defer, 'promiscuous/publisher/mongoid/defer'
|
3
4
|
|
4
5
|
include Promiscuous::Publisher::Class
|
5
6
|
include Promiscuous::Publisher::Attributes
|
@@ -13,6 +14,11 @@ class Promiscuous::Publisher::Mongoid < Promiscuous::Publisher::Base
|
|
13
14
|
include Promiscuous::Publisher::Mongoid::Embedded
|
14
15
|
else
|
15
16
|
include Promiscuous::Publisher::Model
|
17
|
+
include Promiscuous::Publisher::Mongoid::Defer if mongoid3?
|
16
18
|
end
|
17
19
|
end
|
20
|
+
|
21
|
+
def self.mongoid3?
|
22
|
+
Gem.loaded_specs['mongoid'].version >= Gem::Version.new('3.0.0')
|
23
|
+
end
|
18
24
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
class Promiscuous::Publisher::Worker
|
2
|
+
include Promiscuous::Common::Worker
|
3
|
+
|
4
|
+
def self.poll_delay
|
5
|
+
# TODO Configurable globally
|
6
|
+
# TODO Configurable per publisher
|
7
|
+
1.second
|
8
|
+
end
|
9
|
+
|
10
|
+
def replicate
|
11
|
+
EM.defer proc { self.replicate_once },
|
12
|
+
proc { EM::Timer.new(self.class.poll_delay) { replicate } }
|
13
|
+
end
|
14
|
+
|
15
|
+
def replicate_once
|
16
|
+
return if self.stop
|
17
|
+
begin
|
18
|
+
self.unit_of_work do
|
19
|
+
Promiscuous::Publisher::Mongoid::Defer.klasses.values.each do |klass|
|
20
|
+
replicate_collection(klass)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
rescue Exception => e
|
24
|
+
self.stop = true
|
25
|
+
unless e.is_a?(Promiscuous::Publisher::Error)
|
26
|
+
e = Promiscuous::Publisher::Error.new(e, nil)
|
27
|
+
end
|
28
|
+
Promiscuous.error "[publish] FATAL #{e}"
|
29
|
+
Promiscuous::Config.error_handler.try(:call, e)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def replicate_collection(klass)
|
34
|
+
return if self.stop
|
35
|
+
# TODO Check for indexes and if not there, bail out
|
36
|
+
psp_field = klass.aliased_fields["promiscous_sync_pending"]
|
37
|
+
while instance = klass.where(psp_field => true).find_and_modify({'$unset' => {psp_field => 1}})
|
38
|
+
replicate_instance(instance)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def replicate_instance(instance)
|
43
|
+
return if self.stop
|
44
|
+
instance.class.promiscuous_publisher.new(:instance => instance, :operation => :update, :defer => false).publish
|
45
|
+
rescue Exception => e
|
46
|
+
# TODO set back the psp field
|
47
|
+
raise Promiscuous::Publisher::Error.new(e, instance)
|
48
|
+
end
|
49
|
+
end
|
@@ -10,6 +10,8 @@ module Promiscuous::Publisher
|
|
10
10
|
autoload :Model, 'promiscuous/publisher/model'
|
11
11
|
autoload :Mongoid, 'promiscuous/publisher/mongoid'
|
12
12
|
autoload :Polymorphic, 'promiscuous/publisher/polymorphic'
|
13
|
+
autoload :Worker, 'promiscuous/publisher/worker'
|
14
|
+
autoload :Error, 'promiscuous/publisher/error'
|
13
15
|
|
14
16
|
def self.lint(*args)
|
15
17
|
Lint.lint(*args)
|
@@ -1,18 +1,38 @@
|
|
1
1
|
namespace :promiscuous do
|
2
|
-
|
2
|
+
# Note This rake task can be loaded without Rails
|
3
|
+
desc 'Run the workers'
|
3
4
|
task :replicate => :environment do |t|
|
4
|
-
require 'promiscuous/worker'
|
5
5
|
require 'eventmachine'
|
6
6
|
require 'em-synchrony'
|
7
7
|
|
8
8
|
EM.synchrony do
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
Promiscuous::
|
9
|
+
trap_signals
|
10
|
+
force_backend :rubyamqp
|
11
|
+
|
12
|
+
Promiscuous::Loader.load_descriptors if defined?(Rails)
|
13
13
|
|
14
14
|
Promiscuous::Worker.replicate
|
15
|
-
|
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
|
16
20
|
end
|
17
21
|
end
|
22
|
+
|
23
|
+
def trap_signals
|
24
|
+
%w(SIGTERM SIGINT).each do |signal|
|
25
|
+
Signal.trap(signal) do
|
26
|
+
Promiscuous.info "Exiting..."
|
27
|
+
Promiscuous::Worker.stop
|
28
|
+
EM.stop
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def force_backend(backend)
|
34
|
+
Promiscuous::AMQP.disconnect
|
35
|
+
Promiscuous::Config.backend = backend
|
36
|
+
Promiscuous::AMQP.connect
|
37
|
+
end
|
18
38
|
end
|
@@ -16,7 +16,7 @@ module Promiscuous::Subscriber::AMQP
|
|
16
16
|
included { use_option :from }
|
17
17
|
|
18
18
|
module ClassMethods
|
19
|
-
def from=(
|
19
|
+
def from=(_)
|
20
20
|
super
|
21
21
|
old_sub = Promiscuous::Subscriber::AMQP.subscribers[from]
|
22
22
|
raise "The subscriber '#{old_sub}' already listen on '#{from}'" if old_sub
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class Promiscuous::Subscriber::Worker
|
2
|
+
include Promiscuous::Common::Worker
|
3
|
+
|
4
|
+
def replicate
|
5
|
+
Promiscuous::AMQP.subscribe(subscribe_options) do |metadata, payload|
|
6
|
+
# Note: This code always runs on the root Fiber,
|
7
|
+
# so ordering is always preserved
|
8
|
+
begin
|
9
|
+
unless self.stop
|
10
|
+
Promiscuous.info "[receive] #{payload}"
|
11
|
+
self.unit_of_work { Promiscuous::Subscriber.process(JSON.parse(payload)) }
|
12
|
+
metadata.ack
|
13
|
+
end
|
14
|
+
rescue Exception => e
|
15
|
+
e = Promiscuous::Subscriber::Error.new(e, payload)
|
16
|
+
|
17
|
+
# TODO Discuss with Arjun about having an error queue.
|
18
|
+
self.stop = true
|
19
|
+
Promiscuous::AMQP.disconnect
|
20
|
+
Promiscuous.error "[receive] FATAL #{e}"
|
21
|
+
Promiscuous::Config.error_handler.try(:call, e)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def subscribe_options
|
27
|
+
queue_name = "#{Promiscuous::Config.app}.promiscuous"
|
28
|
+
bindings = Promiscuous::Subscriber::AMQP.subscribers.keys
|
29
|
+
{:queue_name => queue_name, :bindings => bindings}
|
30
|
+
end
|
31
|
+
end
|
@@ -12,6 +12,7 @@ module Promiscuous::Subscriber
|
|
12
12
|
autoload :Polymorphic, 'promiscuous/subscriber/polymorphic'
|
13
13
|
autoload :Upsert, 'promiscuous/subscriber/upsert'
|
14
14
|
autoload :Observer, 'promiscuous/subscriber/observer'
|
15
|
+
autoload :Worker, 'promiscuous/subscriber/worker'
|
15
16
|
|
16
17
|
def self.lint(*args)
|
17
18
|
Lint.lint(*args)
|
data/lib/promiscuous/version.rb
CHANGED
data/lib/promiscuous/worker.rb
CHANGED
@@ -1,51 +1,15 @@
|
|
1
|
-
module Promiscuous
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
begin
|
11
|
-
unless self.stop
|
12
|
-
Promiscuous.info "[receive] #{payload}"
|
13
|
-
self.mongoid_wrapper { Promiscuous::Subscriber.process(JSON.parse(payload)) }
|
14
|
-
metadata.ack
|
15
|
-
end
|
16
|
-
rescue Exception => e
|
17
|
-
e = Promiscuous::Subscriber::Error.new(e, payload)
|
18
|
-
|
19
|
-
self.stop = true
|
20
|
-
Promiscuous::AMQP.disconnect
|
21
|
-
Promiscuous.error "[receive] FATAL #{e}"
|
22
|
-
Promiscuous::Config.error_handler.call(e) if Promiscuous::Config.error_handler
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def self.mongoid_wrapper
|
28
|
-
if defined?(Mongoid)
|
29
|
-
Mongoid.unit_of_work { yield }
|
30
|
-
else
|
31
|
-
yield
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def self.trap_signals
|
36
|
-
%w(SIGTERM SIGINT).each do |signal|
|
37
|
-
Signal.trap(signal) do
|
38
|
-
self.stop = true
|
39
|
-
EM.stop
|
40
|
-
Promiscuous.info "exiting gracefully"
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
1
|
+
module Promiscuous::Worker
|
2
|
+
mattr_accessor :workers
|
3
|
+
self.workers = []
|
4
|
+
|
5
|
+
def self.replicate
|
6
|
+
self.workers << Promiscuous::Publisher::Worker.new
|
7
|
+
self.workers << Promiscuous::Subscriber::Worker.new
|
8
|
+
self.workers.each { |w| w.replicate }
|
9
|
+
end
|
44
10
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
{:queue_name => queue_name, :bindings => bindings}
|
49
|
-
end
|
11
|
+
def self.stop
|
12
|
+
self.workers.each { |w| w.stop = true }
|
13
|
+
self.workers.clear
|
50
14
|
end
|
51
15
|
end
|
data/lib/promiscuous.rb
CHANGED
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.10'
|
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-10-
|
13
|
+
date: 2012-10-10 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activesupport
|
@@ -105,8 +105,8 @@ files:
|
|
105
105
|
- lib/promiscuous/amqp/rubyamqp.rb
|
106
106
|
- lib/promiscuous/publisher/envelope.rb
|
107
107
|
- lib/promiscuous/publisher/mongoid/embedded.rb
|
108
|
+
- lib/promiscuous/publisher/mongoid/defer.rb
|
108
109
|
- lib/promiscuous/publisher/active_record.rb
|
109
|
-
- lib/promiscuous/publisher/amqp.rb
|
110
110
|
- lib/promiscuous/publisher/attributes.rb
|
111
111
|
- lib/promiscuous/publisher/base.rb
|
112
112
|
- lib/promiscuous/publisher/lint.rb
|
@@ -115,17 +115,19 @@ files:
|
|
115
115
|
- lib/promiscuous/publisher/lint/base.rb
|
116
116
|
- lib/promiscuous/publisher/lint/class.rb
|
117
117
|
- lib/promiscuous/publisher/lint/polymorphic.rb
|
118
|
-
- lib/promiscuous/publisher/mongoid.rb
|
119
118
|
- lib/promiscuous/publisher/polymorphic.rb
|
120
|
-
- lib/promiscuous/publisher/model.rb
|
121
119
|
- lib/promiscuous/publisher/class.rb
|
122
120
|
- lib/promiscuous/publisher/mock.rb
|
121
|
+
- lib/promiscuous/publisher/amqp.rb
|
122
|
+
- lib/promiscuous/publisher/error.rb
|
123
|
+
- lib/promiscuous/publisher/model.rb
|
124
|
+
- lib/promiscuous/publisher/mongoid.rb
|
125
|
+
- lib/promiscuous/publisher/worker.rb
|
123
126
|
- lib/promiscuous/railtie/replicate.rake
|
124
127
|
- lib/promiscuous/subscriber/envelope.rb
|
125
128
|
- lib/promiscuous/subscriber/error.rb
|
126
129
|
- lib/promiscuous/subscriber/mongoid/embedded.rb
|
127
130
|
- lib/promiscuous/subscriber/active_record.rb
|
128
|
-
- lib/promiscuous/subscriber/amqp.rb
|
129
131
|
- lib/promiscuous/subscriber/lint.rb
|
130
132
|
- lib/promiscuous/subscriber/lint/amqp.rb
|
131
133
|
- lib/promiscuous/subscriber/lint/base.rb
|
@@ -137,23 +139,26 @@ files:
|
|
137
139
|
- lib/promiscuous/subscriber/upsert.rb
|
138
140
|
- lib/promiscuous/subscriber/model.rb
|
139
141
|
- lib/promiscuous/subscriber/class.rb
|
140
|
-
- lib/promiscuous/subscriber/polymorphic.rb
|
141
|
-
- lib/promiscuous/subscriber/attributes.rb
|
142
142
|
- lib/promiscuous/subscriber/observer.rb
|
143
|
+
- lib/promiscuous/subscriber/attributes.rb
|
144
|
+
- lib/promiscuous/subscriber/amqp.rb
|
145
|
+
- lib/promiscuous/subscriber/polymorphic.rb
|
146
|
+
- lib/promiscuous/subscriber/worker.rb
|
143
147
|
- lib/promiscuous/config.rb
|
144
148
|
- lib/promiscuous/amqp.rb
|
145
149
|
- lib/promiscuous/common/lint.rb
|
146
150
|
- lib/promiscuous/common/lint/base.rb
|
147
151
|
- lib/promiscuous/common/options.rb
|
148
152
|
- lib/promiscuous/common/class_helpers.rb
|
153
|
+
- lib/promiscuous/common/worker.rb
|
149
154
|
- lib/promiscuous/loader.rb
|
150
|
-
- lib/promiscuous/publisher.rb
|
151
155
|
- lib/promiscuous/railtie.rb
|
152
|
-
- lib/promiscuous/worker.rb
|
153
|
-
- lib/promiscuous/common.rb
|
154
156
|
- lib/promiscuous/observer.rb
|
157
|
+
- lib/promiscuous/common.rb
|
158
|
+
- lib/promiscuous/publisher.rb
|
155
159
|
- lib/promiscuous/subscriber.rb
|
156
160
|
- lib/promiscuous/version.rb
|
161
|
+
- lib/promiscuous/worker.rb
|
157
162
|
- lib/promiscuous.rb
|
158
163
|
- README.md
|
159
164
|
homepage: http://github.com/crowdtap/promiscuous
|