messaging 3.4.2 → 3.5.4

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.
@@ -23,7 +23,8 @@ module Messaging
23
23
  self.expected_version = message.expected_version
24
24
  self.message_type = message.message_type
25
25
  self.stream = message.stream_name
26
- self.stream_category, self.stream_id = message.stream_name.split('$')
26
+ self.stream_category = message.stream_category
27
+ self.stream_id = message.stream_id
27
28
  self.uuid = message.uuid
28
29
  end
29
30
 
@@ -1,3 +1,5 @@
1
+ require_relative 'category'
2
+ require_relative 'categories'
1
3
  require_relative 'stream'
2
4
  require_relative 'streams'
3
5
 
@@ -20,11 +22,16 @@ module Messaging
20
22
  # @see Streams
21
23
  attr_reader :streams
22
24
 
25
+ # @return [Categories] all the stream categories in the store
26
+ # @see Categories
27
+ attr_reader :categories
28
+
23
29
  # Should not be used directly. Access the store though
24
30
  # Messaging.message_store or Messaging::Adapters::Store[:postgres]
25
31
  # @api private
26
32
  def initialize
27
33
  @streams = Streams.new
34
+ @categories = Categories.new
28
35
  end
29
36
 
30
37
  # Get a specific stream by name
@@ -34,6 +41,13 @@ module Messaging
34
41
  streams[name]
35
42
  end
36
43
 
44
+ # Get a specific category by name
45
+ # @return [Stream]
46
+ # @see Messaging.category
47
+ def category(name)
48
+ categories[name]
49
+ end
50
+
37
51
  # Access to all messages.
38
52
  # Use with caution in production as there are probably
39
53
  # a lot of messages so queries could take a long time or timeout.
@@ -48,6 +62,15 @@ module Messaging
48
62
  SerializedMessage
49
63
  end
50
64
 
65
+ # Access to all messages in the given streams
66
+ #
67
+ # @param streams [Array<String, Stream>] List of one or more streams to get messages from
68
+ # @return [ActiveRecord::Relation]
69
+ # @see Messaging.messages_in_streams
70
+ def messages_in_streams(*streams)
71
+ SerializedMessage.where(stream: streams.flatten.map(&:to_s)).order(:id)
72
+ end
73
+
51
74
  # Writes the message to Postgres
52
75
  # Skips messages that hasn't defined a stream name
53
76
  # We do this to begin with so PG is opt-in per message
@@ -27,6 +27,10 @@ module Messaging
27
27
  messages.maximum(:stream_position) || -1
28
28
  end
29
29
 
30
+ def to_s
31
+ name
32
+ end
33
+
30
34
  def inspect
31
35
  info = "current_position: #{current_position}"
32
36
  "#<Stream:#{name}> #{info}>"
@@ -0,0 +1,19 @@
1
+ module Messaging
2
+ module Adapters
3
+ class Test
4
+ class Categories
5
+ def initialize
6
+ clear!
7
+ end
8
+
9
+ def [](name)
10
+ @categories[name]
11
+ end
12
+
13
+ def clear!
14
+ @categories = Hash.new { |h, k| h[k] = Category.new(k) }
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ module Messaging
2
+ module Adapters
3
+ class Test
4
+ class Category
5
+ attr_accessor :name
6
+
7
+ def initialize(name)
8
+ self.name = name
9
+ end
10
+
11
+ def messages
12
+ @messages ||= []
13
+ end
14
+
15
+ def delete_messages_older_than!(time)
16
+ messages.delete_if { |m| m.timestamp < time }
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,4 +1,6 @@
1
1
  require_relative 'stream'
2
+ require_relative 'category'
3
+ require_relative 'categories'
2
4
 
3
5
  module Messaging
4
6
  module Adapters
@@ -29,7 +31,10 @@ module Messaging
29
31
  # @see Stream
30
32
  attr_reader :streams
31
33
 
34
+ attr_reader :categories
35
+
32
36
  def initialize
37
+ @categories = Categories.new
33
38
  clear!
34
39
  end
35
40
 
@@ -40,8 +45,21 @@ module Messaging
40
45
  streams[name]
41
46
  end
42
47
 
48
+ def category(name)
49
+ categories[name]
50
+ end
51
+
52
+ # Access to all messages in the given streams
53
+ #
54
+ # @param streams [Array<String>] List of one or more streams to get messages from
55
+ # @return [Array<Messaging::Message>]
56
+ def messages_in_streams(*streams)
57
+ messages.select { |m| streams.flatten.map(&:to_s).include? m.stream_name }
58
+ end
59
+
43
60
  def clear!
44
61
  @streams = Hash.new { |h, k| h[k] = Stream.new(k) }
62
+ categories.clear!
45
63
  @messages = []
46
64
  end
47
65
 
@@ -55,10 +73,12 @@ module Messaging
55
73
  return message unless message.stream_name
56
74
 
57
75
  stream = stream(message.stream_name)
76
+ category = category(message.stream_name.split('$').first)
58
77
  ExpectedVersion.new(message.expected_version || :any).match!(stream.current_position)
59
78
  persisted_message = message.class.new(message.attributes.merge(stream_position: stream.current_position + 1))
60
79
  @messages << persisted_message
61
80
  stream.messages << persisted_message
81
+ category.messages << persisted_message
62
82
  persisted_message
63
83
  end
64
84
  end
@@ -12,6 +12,10 @@ module Messaging
12
12
  @messages ||= []
13
13
  end
14
14
 
15
+ def to_s
16
+ name
17
+ end
18
+
15
19
  def current_position
16
20
  messages.length - 1
17
21
  end
@@ -92,6 +92,18 @@ module Messaging
92
92
  nil
93
93
  end
94
94
 
95
+ def stream_category
96
+ return unless stream_name
97
+
98
+ stream_name.split('$').first
99
+ end
100
+
101
+ def stream_id
102
+ return unless stream_name
103
+
104
+ stream_name.split('$').last
105
+ end
106
+
95
107
  def message_type
96
108
  self.class.to_s
97
109
  end
@@ -22,6 +22,19 @@ module Messaging
22
22
  end
23
23
  end
24
24
 
25
+ def inline!(&block)
26
+ current_routes = @routes.dup
27
+ consumer_definitions.each do |_, definition|
28
+ definition.fetch(:block)&.call(self)
29
+ end
30
+
31
+ block.call
32
+
33
+ ensure
34
+ clear_routes!
35
+ @routes = current_routes
36
+ end
37
+
25
38
  # Keeps the consumers, but reload their subscriptions so code reloading works.
26
39
  # The consumer has a reference to the class name of each of its handlers,
27
40
  # if the handler is reloaded the reference would point to an old instance.
@@ -5,6 +5,32 @@ require 'messaging/routing/enqueue_message_handler'
5
5
 
6
6
  module Messaging
7
7
  module Routing
8
+ def self.included(base)
9
+ base.send :extend, ClassMethods
10
+ end
11
+
12
+ module ClassMethods
13
+ def definitions
14
+ @definitions ||= []
15
+ end
16
+
17
+ def on(pattern, **options, &block)
18
+ definitions << { pattern: pattern, options: options, block: block }
19
+ end
20
+
21
+ def new(*args, &block)
22
+ instance = allocate
23
+
24
+ # Pre-initialize
25
+ definitions.each do |definition|
26
+ instance.on(definition[:pattern], definition[:options], &definition[:block])
27
+ end
28
+
29
+ instance.send(:initialize, *args, &block)
30
+ instance
31
+ end
32
+ end
33
+
8
34
  # Public: Sets up routes for the events that matches the given pattern
9
35
  #
10
36
  # pattern - Which messages to route. Can be a string, a regexp,
@@ -44,8 +70,8 @@ module Messaging
44
70
  end
45
71
 
46
72
  # Internal: Handles the message with the matching subscribers
47
- def handle(message)
48
- routes.map { |route| route.call(message) }
73
+ def handle(message, context = self)
74
+ routes.map { |route| route.call(message, context) }
49
75
  message
50
76
  end
51
77
 
@@ -4,7 +4,7 @@ module Messaging
4
4
  class EnqueuedRoute < Route
5
5
  def initialize(pattern, handler)
6
6
  super
7
- @handler = EnqueueMessageHandler.new(handler)
7
+ @handler = EnqueueMessageHandler.new(handler).method(:call)
8
8
  end
9
9
  end
10
10
  end
@@ -11,14 +11,14 @@ module Messaging
11
11
 
12
12
  def initialize(pattern, handler)
13
13
  @matcher = MessageMatcher.new(pattern: pattern)
14
- @handler = handler
14
+ @handler = handler.respond_to?(:to_proc) ? handler : handler.method(:call)
15
15
  verify_handler!
16
16
  end
17
17
 
18
- def call(message)
18
+ def call(message, context = self)
19
19
  return unless @matcher.matches?(message)
20
20
 
21
- @handler.call(message)
21
+ context.instance_exec(message, &@handler)
22
22
  end
23
23
 
24
24
  def topics
@@ -1,3 +1,3 @@
1
1
  module Messaging
2
- VERSION = '3.4.2'.freeze
2
+ VERSION = '3.5.4'.freeze
3
3
  end
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_dependency 'activerecord'
22
22
  spec.add_dependency 'activesupport'
23
- spec.add_dependency 'bukowskis_after_transaction'
23
+ spec.add_dependency 'after_transaction'
24
24
  spec.add_dependency 'method_object'
25
25
  spec.add_dependency 'concurrent-ruby', '>= 1.0.2'
26
26
  spec.add_dependency 'concurrent-ruby-ext', '>= 1.0.2'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: messaging
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.4.2
4
+ version: 3.5.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bukowskis
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-11-14 00:00:00.000000000 Z
11
+ date: 2020-05-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -39,7 +39,7 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: bukowskis_after_transaction
42
+ name: after_transaction
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
@@ -279,8 +279,16 @@ files:
279
279
  - README.md
280
280
  - Rakefile
281
281
  - _config.yml
282
+ - _data/navigation.yml
283
+ - _layouts/single.html
282
284
  - bin/console
283
285
  - bin/setup
286
+ - docs/adapters.md
287
+ - docs/consuming.md
288
+ - docs/installation.md
289
+ - docs/messages.md
290
+ - docs/publishing.md
291
+ - docs/routing_and_handlers.md
284
292
  - exe/messaging
285
293
  - lib/messaging.rb
286
294
  - lib/messaging/adapters.rb
@@ -289,15 +297,18 @@ files:
289
297
  - lib/messaging/adapters/kafka/producer.rb
290
298
  - lib/messaging/adapters/postgres.rb
291
299
  - lib/messaging/adapters/postgres/advisory_transaction_lock.rb
300
+ - lib/messaging/adapters/postgres/categories.rb
301
+ - lib/messaging/adapters/postgres/category.rb
292
302
  - lib/messaging/adapters/postgres/serialized_message.rb
293
303
  - lib/messaging/adapters/postgres/store.rb
294
304
  - lib/messaging/adapters/postgres/stream.rb
295
305
  - lib/messaging/adapters/postgres/streams.rb
296
306
  - lib/messaging/adapters/test.rb
307
+ - lib/messaging/adapters/test/categories.rb
308
+ - lib/messaging/adapters/test/category.rb
297
309
  - lib/messaging/adapters/test/consumer.rb
298
310
  - lib/messaging/adapters/test/store.rb
299
311
  - lib/messaging/adapters/test/stream.rb
300
- - lib/messaging/base_handler.rb
301
312
  - lib/messaging/cli.rb
302
313
  - lib/messaging/config.rb
303
314
  - lib/messaging/consumer_supervisor.rb
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Messaging
4
- # @private
5
- # @deprecated
6
- class BaseHandler
7
- class << self
8
- def only_messages(messages = nil)
9
- @only_messages = Array(messages) if messages
10
- @only_messages || []
11
- end
12
- alias only_message only_messages
13
-
14
- def group_id(group_id = nil)
15
- @group_id = group_id if group_id
16
- @group_id || default_group_id
17
- end
18
-
19
- def default_group_id
20
- Config.app_name + '-' + name.underscore
21
- end
22
-
23
- def call(message)
24
- return unless allowed_message?(message.class)
25
-
26
- new.on_message(message, nil)
27
- end
28
-
29
- def listen_on(topic:)
30
- topics = Array(topic).map(&:to_s)
31
- Messaging.routes.consumer(name, group_id: group_id) do |c|
32
- topics.each { |t| c.on(->(m) { m.topic == t }, call: self) }
33
- end
34
- end
35
-
36
- def allowed_message?(message_class)
37
- return true if only_messages.empty?
38
-
39
- only_messages.include? message_class
40
- end
41
- end
42
-
43
- def on_message(message, _metadata); end
44
- end
45
- end