promiscuous 0.53.1 → 0.90.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.
Files changed (106) hide show
  1. data/lib/promiscuous.rb +25 -28
  2. data/lib/promiscuous/amqp.rb +27 -8
  3. data/lib/promiscuous/amqp/bunny.rb +131 -16
  4. data/lib/promiscuous/amqp/fake.rb +52 -0
  5. data/lib/promiscuous/amqp/hot_bunnies.rb +56 -0
  6. data/lib/promiscuous/amqp/null.rb +6 -6
  7. data/lib/promiscuous/cli.rb +108 -24
  8. data/lib/promiscuous/config.rb +73 -12
  9. data/lib/promiscuous/convenience.rb +18 -0
  10. data/lib/promiscuous/dependency.rb +59 -0
  11. data/lib/promiscuous/dsl.rb +36 -0
  12. data/lib/promiscuous/error.rb +3 -1
  13. data/lib/promiscuous/error/already_processed.rb +5 -0
  14. data/lib/promiscuous/error/base.rb +1 -0
  15. data/lib/promiscuous/error/connection.rb +7 -5
  16. data/lib/promiscuous/error/dependency.rb +111 -0
  17. data/lib/promiscuous/error/lock_unavailable.rb +12 -0
  18. data/lib/promiscuous/error/lost_lock.rb +12 -0
  19. data/lib/promiscuous/error/missing_context.rb +29 -0
  20. data/lib/promiscuous/error/publisher.rb +5 -15
  21. data/lib/promiscuous/error/recovery.rb +7 -0
  22. data/lib/promiscuous/error/subscriber.rb +2 -4
  23. data/lib/promiscuous/key.rb +36 -0
  24. data/lib/promiscuous/loader.rb +12 -16
  25. data/lib/promiscuous/middleware.rb +112 -0
  26. data/lib/promiscuous/publisher.rb +7 -4
  27. data/lib/promiscuous/publisher/context.rb +92 -0
  28. data/lib/promiscuous/publisher/mock_generator.rb +72 -0
  29. data/lib/promiscuous/publisher/model.rb +3 -86
  30. data/lib/promiscuous/publisher/model/active_record.rb +8 -15
  31. data/lib/promiscuous/publisher/model/base.rb +136 -0
  32. data/lib/promiscuous/publisher/model/ephemeral.rb +69 -0
  33. data/lib/promiscuous/publisher/model/mock.rb +61 -0
  34. data/lib/promiscuous/publisher/model/mongoid.rb +57 -100
  35. data/lib/promiscuous/{common/lint.rb → publisher/operation.rb} +1 -1
  36. data/lib/promiscuous/publisher/operation/base.rb +707 -0
  37. data/lib/promiscuous/publisher/operation/mongoid.rb +370 -0
  38. data/lib/promiscuous/publisher/worker.rb +22 -0
  39. data/lib/promiscuous/railtie.rb +21 -3
  40. data/lib/promiscuous/redis.rb +132 -40
  41. data/lib/promiscuous/resque.rb +12 -0
  42. data/lib/promiscuous/sidekiq.rb +15 -0
  43. data/lib/promiscuous/subscriber.rb +9 -20
  44. data/lib/promiscuous/subscriber/model.rb +4 -104
  45. data/lib/promiscuous/subscriber/model/active_record.rb +10 -0
  46. data/lib/promiscuous/subscriber/model/base.rb +96 -0
  47. data/lib/promiscuous/subscriber/model/mongoid.rb +86 -0
  48. data/lib/promiscuous/subscriber/model/observer.rb +37 -0
  49. data/lib/promiscuous/subscriber/operation.rb +167 -0
  50. data/lib/promiscuous/subscriber/payload.rb +34 -0
  51. data/lib/promiscuous/subscriber/worker.rb +22 -18
  52. data/lib/promiscuous/subscriber/worker/message.rb +48 -25
  53. data/lib/promiscuous/subscriber/worker/message_synchronizer.rb +273 -181
  54. data/lib/promiscuous/subscriber/worker/pump.rb +17 -43
  55. data/lib/promiscuous/subscriber/worker/recorder.rb +24 -0
  56. data/lib/promiscuous/subscriber/worker/runner.rb +24 -3
  57. data/lib/promiscuous/subscriber/worker/stats.rb +62 -0
  58. data/lib/promiscuous/timer.rb +38 -0
  59. data/lib/promiscuous/version.rb +1 -1
  60. metadata +98 -143
  61. data/README.md +0 -33
  62. data/lib/promiscuous/amqp/ruby_amqp.rb +0 -140
  63. data/lib/promiscuous/common.rb +0 -4
  64. data/lib/promiscuous/common/class_helpers.rb +0 -12
  65. data/lib/promiscuous/common/lint/base.rb +0 -24
  66. data/lib/promiscuous/common/options.rb +0 -51
  67. data/lib/promiscuous/ephemeral.rb +0 -14
  68. data/lib/promiscuous/error/recover.rb +0 -1
  69. data/lib/promiscuous/observer.rb +0 -5
  70. data/lib/promiscuous/publisher/active_record.rb +0 -7
  71. data/lib/promiscuous/publisher/amqp.rb +0 -18
  72. data/lib/promiscuous/publisher/attributes.rb +0 -32
  73. data/lib/promiscuous/publisher/base.rb +0 -23
  74. data/lib/promiscuous/publisher/class.rb +0 -36
  75. data/lib/promiscuous/publisher/envelope.rb +0 -7
  76. data/lib/promiscuous/publisher/ephemeral.rb +0 -9
  77. data/lib/promiscuous/publisher/lint.rb +0 -35
  78. data/lib/promiscuous/publisher/lint/amqp.rb +0 -14
  79. data/lib/promiscuous/publisher/lint/attributes.rb +0 -12
  80. data/lib/promiscuous/publisher/lint/base.rb +0 -5
  81. data/lib/promiscuous/publisher/lint/class.rb +0 -15
  82. data/lib/promiscuous/publisher/lint/polymorphic.rb +0 -22
  83. data/lib/promiscuous/publisher/mock.rb +0 -79
  84. data/lib/promiscuous/publisher/mongoid.rb +0 -33
  85. data/lib/promiscuous/publisher/mongoid/embedded.rb +0 -27
  86. data/lib/promiscuous/publisher/mongoid/embedded_many.rb +0 -12
  87. data/lib/promiscuous/publisher/polymorphic.rb +0 -8
  88. data/lib/promiscuous/subscriber/active_record.rb +0 -11
  89. data/lib/promiscuous/subscriber/amqp.rb +0 -25
  90. data/lib/promiscuous/subscriber/attributes.rb +0 -35
  91. data/lib/promiscuous/subscriber/base.rb +0 -29
  92. data/lib/promiscuous/subscriber/class.rb +0 -29
  93. data/lib/promiscuous/subscriber/dummy.rb +0 -19
  94. data/lib/promiscuous/subscriber/envelope.rb +0 -18
  95. data/lib/promiscuous/subscriber/lint.rb +0 -30
  96. data/lib/promiscuous/subscriber/lint/amqp.rb +0 -21
  97. data/lib/promiscuous/subscriber/lint/attributes.rb +0 -21
  98. data/lib/promiscuous/subscriber/lint/base.rb +0 -14
  99. data/lib/promiscuous/subscriber/lint/class.rb +0 -13
  100. data/lib/promiscuous/subscriber/lint/polymorphic.rb +0 -39
  101. data/lib/promiscuous/subscriber/mongoid.rb +0 -27
  102. data/lib/promiscuous/subscriber/mongoid/embedded.rb +0 -17
  103. data/lib/promiscuous/subscriber/mongoid/embedded_many.rb +0 -44
  104. data/lib/promiscuous/subscriber/observer.rb +0 -26
  105. data/lib/promiscuous/subscriber/polymorphic.rb +0 -36
  106. data/lib/promiscuous/subscriber/upsert.rb +0 -12
@@ -1,35 +0,0 @@
1
- module Promiscuous::Publisher::Lint
2
- extend Promiscuous::Autoload
3
- autoload :Base, :Class, :Attributes, :Polymorphic, :AMQP
4
-
5
- def self.get_publisher(klass)
6
- unless klass.respond_to?(:promiscuous_publisher)
7
- raise "#{klass} has no publisher"
8
- end
9
-
10
- klass.promiscuous_publisher
11
- end
12
-
13
- def self.lint(class_bindings={})
14
- if class_bindings.empty?
15
- class_bindings = Promiscuous::Publisher::Model.klasses.reduce({}) do |res, klass|
16
- res[klass] = klass.promiscuous_publisher.to
17
- res
18
- end
19
-
20
- raise "No publishers found" if class_bindings.empty?
21
- end
22
-
23
- class_bindings.each do |klass, to|
24
- pub = get_publisher(klass)
25
-
26
- lint = ::Class.new(Base)
27
- lint.__send__(:include, Class) if pub.include?(Promiscuous::Publisher::Class)
28
- lint.__send__(:include, Attributes) if pub.include?(Promiscuous::Publisher::Attributes)
29
- lint.__send__(:include, AMQP) if pub.include?(Promiscuous::Publisher::AMQP)
30
- lint.__send__(:include, Polymorphic) if pub.include?(Promiscuous::Publisher::Polymorphic)
31
- lint.new(:klass => klass, :publisher => pub, :to => to).lint
32
- end
33
- true
34
- end
35
- end
@@ -1,14 +0,0 @@
1
- module Promiscuous::Publisher::Lint::AMQP
2
- extend ActiveSupport::Concern
3
-
4
- def lint
5
- super
6
-
7
- pub_to = publisher.to
8
- if pub_to != to
9
- raise "#{publisher} publishes #{klass} to #{pub_to} instead of #{to}"
10
- end
11
- end
12
-
13
- included { use_option :to }
14
- end
@@ -1,12 +0,0 @@
1
- module Promiscuous::Publisher::Lint::Attributes
2
- extend ActiveSupport::Concern
3
-
4
- def lint
5
- super
6
-
7
- instance = klass.new
8
- publisher.attributes.each do |attr|
9
- instance.respond_to?(attr) or instance.__send__(attr)
10
- end
11
- end
12
- end
@@ -1,5 +0,0 @@
1
- class Promiscuous::Publisher::Lint::Base
2
- include Promiscuous::Common::Lint::Base
3
-
4
- use_option(:publisher)
5
- end
@@ -1,15 +0,0 @@
1
- module Promiscuous::Publisher::Lint::Class
2
- extend ActiveSupport::Concern
3
-
4
- def lint
5
- super
6
-
7
- if publisher.klass != klass
8
- msg = "Please define a publisher for #{klass}"
9
- msg = "#{msg} because #{parent} is published and you need to cover subclasses" if parent
10
- raise msg
11
- end
12
- end
13
-
14
- included { use_option :klass, :parent }
15
- end
@@ -1,22 +0,0 @@
1
- module Promiscuous::Publisher::Lint::Polymorphic
2
- extend ActiveSupport::Concern
3
-
4
- def lint
5
- super
6
-
7
- unless skip_polymorphic
8
- klass.descendants.each do |subclass|
9
- pub = Promiscuous::Publisher::Lint.get_publisher(subclass)
10
- self.class.new(options.merge(:klass => subclass,
11
- :publisher => pub,
12
- :parent => klass,
13
- :skip_polymorphic => true)).lint
14
- end
15
- end
16
- end
17
-
18
- included do
19
- use_option :klass
20
- use_option :skip_polymorphic
21
- end
22
- end
@@ -1,79 +0,0 @@
1
- class Promiscuous::Publisher::Mock
2
- include Promiscuous::Common::ClassHelpers
3
-
4
- def self.publish(options)
5
- if defined?(attributes)
6
- if options[:attributes]
7
- raise "Do not specify the 'to' field in childrens" if options[:to]
8
- self.attributes = self.attributes + options[:attributes]
9
- end
10
- else
11
- class_attribute :to, :attributes, :klass
12
-
13
- self.to = options[:to]
14
- self.klass = options[:class]
15
- self.attributes = options[:attributes].to_a
16
-
17
- attr_accessor :id, :new_record
18
- end
19
- attr_accessor *attributes
20
-
21
- associations = attributes.map { |attr| $1 if attr =~ /^(.*)_id$/ }.compact
22
- associations.each do |attr|
23
- attr_accessor attr
24
- define_method("#{attr}=") do |value|
25
- instance_variable_set("@#{attr}", value)
26
- instance_variable_set("@#{attr}_id", value.nil? ? value : value.id)
27
- end
28
- end
29
- end
30
-
31
- def self.class_name
32
- self.klass ? self.klass : guess_class_name('Publishers')
33
- end
34
-
35
- def initialize
36
- self.id = BSON::ObjectId.new
37
- self.new_record = true
38
- end
39
-
40
- def save
41
- if payload['__amqp__'].in? Promiscuous::Subscriber::AMQP.subscribers.keys
42
- Promiscuous::Subscriber.process(JSON.parse(payload.to_json))
43
- end
44
- self.new_record = false
45
- true
46
- end
47
- alias :save! :save
48
-
49
- def update_attributes(attrs)
50
- attrs.each { |attr, value| __send__("#{attr}=", value) }
51
- save
52
- end
53
- alias :update_attributes! :update_attributes
54
-
55
- def payload
56
- {
57
- '__amqp__' => self.class.to,
58
- 'id' => self.id,
59
- 'type' => self.class.class_name,
60
- 'operation' => self.new_record ? 'create' : 'update',
61
- 'payload' => Hash[self.class.attributes.map { |attr| [attr.to_s, payload_for(attr)] }]
62
- }
63
- end
64
-
65
- def payload_for(attr)
66
- value = __send__(attr)
67
- value = value.payload if value.is_a?(Promiscuous::Publisher::Mock)
68
- value
69
- end
70
-
71
- def destroy
72
- Promiscuous::Subscriber.process(
73
- '__amqp__' => self.class.to,
74
- 'id' => self.id,
75
- 'type' => self.class.class_name,
76
- 'operation' => 'destroy'
77
- )
78
- end
79
- end
@@ -1,33 +0,0 @@
1
- class Promiscuous::Publisher::Mongoid < Promiscuous::Publisher::Base
2
- extend Promiscuous::Autoload
3
- autoload :Embedded, :EmbeddedMany
4
-
5
- include Promiscuous::Publisher::Class
6
- include Promiscuous::Publisher::Attributes
7
- include Promiscuous::Publisher::Polymorphic
8
- include Promiscuous::Publisher::AMQP
9
-
10
- def self.publish(options)
11
- check_mongoid_version
12
- super
13
-
14
- if klass.embedded?
15
- include Promiscuous::Publisher::Mongoid::Embedded
16
- else
17
- include Promiscuous::Publisher::Model
18
- include Promiscuous::Publisher::Model::Mongoid
19
- end
20
-
21
- setup_class_binding
22
- end
23
-
24
- def self.check_mongoid_version
25
- unless Gem.loaded_specs['mongoid'].version >= Gem::Version.new('3.0.19')
26
- raise "mongoid > 3.0.19 please"
27
- end
28
-
29
- unless Gem.loaded_specs['moped'].version >= Gem::Version.new('1.3.2')
30
- raise "moped > 1.3.2 please"
31
- end
32
- end
33
- end
@@ -1,27 +0,0 @@
1
- module Promiscuous::Publisher::Mongoid::Embedded
2
- extend ActiveSupport::Concern
3
-
4
- def payload
5
- if instance.is_a?(Array)
6
- Promiscuous::Publisher::Mongoid::EmbeddedMany.new(:instance => instance).payload
7
- else
8
- super.merge(:id => instance.id)
9
- end
10
- end
11
-
12
- included do
13
- klass.class_eval do
14
- callback = proc do
15
- if _parent.respond_to?(:with_promiscuous)
16
- _parent.save
17
- # XXX FIXME mongoid needs help, and we need to deal with that.
18
- # We'll address that once we hook on moped
19
- end
20
- end
21
-
22
- after_create callback
23
- after_update callback
24
- after_destroy callback
25
- end
26
- end
27
- end
@@ -1,12 +0,0 @@
1
- class Promiscuous::Publisher::Mongoid::EmbeddedMany < Promiscuous::Publisher::Base
2
- module Payload
3
- def payload
4
- instance.map { |e| e.class.promiscuous_publisher.new(:instance => e).payload }
5
- end
6
- end
7
- include Payload
8
-
9
- include Promiscuous::Publisher::AMQP
10
-
11
- publish :to => '__promiscuous__/embedded_many'
12
- end
@@ -1,8 +0,0 @@
1
- module Promiscuous::Publisher::Polymorphic
2
- extend ActiveSupport::Concern
3
- include Promiscuous::Publisher::Envelope
4
-
5
- def payload
6
- super.merge(:type => instance.class.to_s)
7
- end
8
- end
@@ -1,11 +0,0 @@
1
- class Promiscuous::Subscriber::ActiveRecord < Promiscuous::Subscriber::Base
2
- include Promiscuous::Subscriber::Class
3
- include Promiscuous::Subscriber::Attributes
4
- include Promiscuous::Subscriber::AMQP
5
- include Promiscuous::Subscriber::Model
6
- include Promiscuous::Subscriber::Upsert
7
-
8
- def self.missing_record_exception
9
- ActiveRecord::RecordNotFound
10
- end
11
- end
@@ -1,25 +0,0 @@
1
- module Promiscuous::Subscriber::AMQP
2
- extend ActiveSupport::Concern
3
- include Promiscuous::Subscriber::Envelope
4
-
5
- mattr_accessor :subscribers
6
- self.subscribers = {}
7
-
8
- def self.subscriber_from(payload)
9
- if key = payload.is_a?(Hash) ? payload['__amqp__'] : nil
10
- sub = self.subscribers[key]
11
- sub ||= Promiscuous::Subscriber::Dummy
12
- end
13
- end
14
-
15
- included { use_option :from }
16
-
17
- module ClassMethods
18
- def from=(_)
19
- super
20
- old_sub = Promiscuous::Subscriber::AMQP.subscribers[from]
21
- raise "The subscriber '#{old_sub}' already listen on '#{from}'" if old_sub
22
- Promiscuous::Subscriber::AMQP.subscribers[from] = self
23
- end
24
- end
25
- end
@@ -1,35 +0,0 @@
1
- module Promiscuous::Subscriber::Attributes
2
- extend ActiveSupport::Concern
3
-
4
- def process
5
- super
6
- return unless process_attributes?
7
-
8
- self.class.attributes.each do |attr|
9
- attr = attr.to_s
10
- unless payload.has_key?(attr)
11
- raise "Attribute '#{attr}' is missing from the payload"
12
- end
13
-
14
- options = {}
15
- options[:parent] = instance
16
- options[:old_value] = instance.__send__(attr) if instance.respond_to?(attr)
17
- sub = Promiscuous::Subscriber.subscriber_for(payload[attr], options)
18
-
19
- sub.process
20
- instance.__send__("#{attr}=", sub.instance) if sub.should_update_parent?
21
- end
22
- end
23
-
24
- def process_attributes?
25
- true
26
- end
27
-
28
- included { use_option :attributes }
29
-
30
- module ClassMethods
31
- def attributes=(value)
32
- super(superclass.attributes.to_a + value)
33
- end
34
- end
35
- end
@@ -1,29 +0,0 @@
1
- class Promiscuous::Subscriber::Base
2
- include Promiscuous::Common::Options
3
-
4
- attr_accessor :options
5
-
6
- def initialize(options)
7
- self.options = options
8
- end
9
-
10
- def payload
11
- options[:payload]
12
- end
13
- alias :instance :payload
14
-
15
- def process
16
- end
17
-
18
- def should_update_parent?
19
- true
20
- end
21
-
22
- def subscribe_options
23
- self.class.options
24
- end
25
-
26
- def self.subscribe(options)
27
- load_options(options)
28
- end
29
- end
@@ -1,29 +0,0 @@
1
- module Promiscuous::Subscriber::Class
2
- extend ActiveSupport::Concern
3
- include Promiscuous::Common::ClassHelpers
4
-
5
- def instance
6
- @instance ||= fetch
7
- end
8
-
9
- included { use_option :class, :as => :klass }
10
-
11
- module ClassMethods
12
- def setup_class_binding; end
13
-
14
- def self.subscribe(options)
15
- super
16
- setup_class_binding
17
- end
18
-
19
- def klass=(value)
20
- super
21
- setup_class_binding
22
- end
23
-
24
- def klass
25
- return nil if name.nil?
26
- "::#{super ? super : guess_class_name('Subscribers')}".constantize
27
- end
28
- end
29
- end
@@ -1,19 +0,0 @@
1
- class Promiscuous::Subscriber::Dummy < Promiscuous::Subscriber::Base
2
- include Promiscuous::Subscriber::Class
3
- include Promiscuous::Subscriber::Attributes
4
- include Promiscuous::Subscriber::AMQP
5
- include Promiscuous::Subscriber::Envelope
6
- include Promiscuous::Subscriber::Model
7
-
8
- class DummyInstance
9
- attr_accessor :id
10
- end
11
-
12
- def klass
13
- DummyInstance
14
- end
15
-
16
- def operation
17
- :dummy
18
- end
19
- end
@@ -1,18 +0,0 @@
1
- module Promiscuous::Subscriber::Envelope
2
- extend ActiveSupport::Concern
3
-
4
- module ClassMethods
5
- def use_payload_attribute(attr, options={})
6
- define_method(attr) do
7
- value = payload_with_envelope[attr.to_s]
8
- value = value.to_sym if options[:symbolize]
9
- value
10
- end
11
- end
12
- end
13
-
14
- included do
15
- alias_method :payload_with_envelope, :payload
16
- use_payload_attribute :payload
17
- end
18
- end