cloudenvoy 0.5.rc1 → 0.6.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.
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ../..
3
3
  specs:
4
- cloudenvoy (0.4.2)
4
+ cloudenvoy (0.5.0)
5
5
  activesupport
6
6
  google-cloud-pubsub (~> 2.0)
7
7
  jwt
@@ -10,7 +10,7 @@ PATH
10
10
  GEM
11
11
  remote: https://rubygems.org/
12
12
  specs:
13
- activesupport (7.0.0)
13
+ activesupport (7.0.2.3)
14
14
  concurrent-ruby (~> 1.0, >= 1.0.2)
15
15
  i18n (>= 1.6, < 2)
16
16
  minitest (>= 5.1)
@@ -18,26 +18,30 @@ GEM
18
18
  addressable (2.8.0)
19
19
  public_suffix (>= 2.0.2, < 5.0)
20
20
  concurrent-ruby (1.1.9)
21
- faraday (1.8.0)
21
+ faraday (1.10.0)
22
22
  faraday-em_http (~> 1.0)
23
23
  faraday-em_synchrony (~> 1.0)
24
24
  faraday-excon (~> 1.1)
25
- faraday-httpclient (~> 1.0.1)
25
+ faraday-httpclient (~> 1.0)
26
+ faraday-multipart (~> 1.0)
26
27
  faraday-net_http (~> 1.0)
27
- faraday-net_http_persistent (~> 1.1)
28
+ faraday-net_http_persistent (~> 1.0)
28
29
  faraday-patron (~> 1.0)
29
30
  faraday-rack (~> 1.0)
30
- multipart-post (>= 1.2, < 3)
31
+ faraday-retry (~> 1.0)
31
32
  ruby2_keywords (>= 0.0.4)
32
33
  faraday-em_http (1.0.0)
33
34
  faraday-em_synchrony (1.0.0)
34
35
  faraday-excon (1.1.0)
35
36
  faraday-httpclient (1.0.1)
37
+ faraday-multipart (1.0.3)
38
+ multipart-post (>= 1.2, < 3)
36
39
  faraday-net_http (1.0.1)
37
40
  faraday-net_http_persistent (1.2.0)
38
41
  faraday-patron (1.0.0)
39
42
  faraday-rack (1.0.0)
40
- gapic-common (0.7.0)
43
+ faraday-retry (1.0.3)
44
+ gapic-common (0.8.0)
41
45
  faraday (~> 1.3)
42
46
  google-protobuf (~> 3.14)
43
47
  googleapis-common-protos (>= 1.3.11, < 2.a)
@@ -50,36 +54,40 @@ GEM
50
54
  google-cloud-env (1.5.0)
51
55
  faraday (>= 0.17.3, < 2.0)
52
56
  google-cloud-errors (1.2.0)
53
- google-cloud-pubsub (2.9.0)
57
+ google-cloud-pubsub (2.9.1)
54
58
  concurrent-ruby (~> 1.1)
55
59
  google-cloud-core (~> 1.5)
56
60
  google-cloud-pubsub-v1 (~> 0.0)
57
- google-cloud-pubsub-v1 (0.6.1)
61
+ google-cloud-pubsub-v1 (0.7.1)
58
62
  gapic-common (>= 0.7, < 2.a)
59
63
  google-cloud-errors (~> 1.0)
60
64
  grpc-google-iam-v1 (>= 0.6.10, < 2.a)
61
- google-protobuf (3.19.1-x86_64-darwin)
65
+ google-protobuf (3.19.4-x86_64-darwin)
66
+ google-protobuf (3.19.4-x86_64-linux)
62
67
  googleapis-common-protos (1.3.12)
63
68
  google-protobuf (~> 3.14)
64
69
  googleapis-common-protos-types (~> 1.2)
65
70
  grpc (~> 1.27)
66
71
  googleapis-common-protos-types (1.3.0)
67
72
  google-protobuf (~> 3.14)
68
- googleauth (1.1.0)
69
- faraday (>= 0.17.3, < 2.0)
73
+ googleauth (1.1.2)
74
+ faraday (>= 0.17.3, < 3.a)
70
75
  jwt (>= 1.4, < 3.0)
71
76
  memoist (~> 0.16)
72
77
  multi_json (~> 1.11)
73
78
  os (>= 0.9, < 2.0)
74
79
  signet (>= 0.16, < 2.a)
75
- grpc (1.40.0-universal-darwin)
76
- google-protobuf (~> 3.15)
80
+ grpc (1.43.1-universal-darwin)
81
+ google-protobuf (~> 3.18)
82
+ googleapis-common-protos-types (~> 1.0)
83
+ grpc (1.43.1-x86_64-linux)
84
+ google-protobuf (~> 3.18)
77
85
  googleapis-common-protos-types (~> 1.0)
78
86
  grpc-google-iam-v1 (1.0.0)
79
87
  google-protobuf (~> 3.14)
80
88
  googleapis-common-protos (>= 1.3.12, < 2.0)
81
89
  grpc (~> 1.27)
82
- i18n (1.8.11)
90
+ i18n (1.10.0)
83
91
  concurrent-ruby (~> 1.0)
84
92
  jwt (2.3.0)
85
93
  memoist (0.16.2)
@@ -91,23 +99,23 @@ GEM
91
99
  nio4r (2.5.8)
92
100
  os (1.1.4)
93
101
  public_suffix (4.0.6)
94
- puma (5.5.2)
102
+ puma (5.6.4)
95
103
  nio4r (~> 2.0)
96
- rack (2.2.3)
97
- rack-protection (2.1.0)
104
+ rack (2.2.4)
105
+ rack-protection (2.2.0)
98
106
  rack
99
107
  rake (13.0.6)
100
108
  retriable (3.1.2)
101
109
  ruby2_keywords (0.0.5)
102
- signet (0.16.0)
110
+ signet (0.16.1)
103
111
  addressable (~> 2.8)
104
- faraday (>= 0.17.3, < 2.0)
112
+ faraday (>= 0.17.5, < 3.0)
105
113
  jwt (>= 1.5, < 3.0)
106
114
  multi_json (~> 1.10)
107
- sinatra (2.1.0)
115
+ sinatra (2.2.0)
108
116
  mustermann (~> 1.0)
109
117
  rack (~> 2.2)
110
- rack-protection (= 2.1.0)
118
+ rack-protection (= 2.2.0)
111
119
  tilt (~> 2.0)
112
120
  tilt (2.0.10)
113
121
  tzinfo (2.0.4)
@@ -116,11 +124,11 @@ GEM
116
124
  PLATFORMS
117
125
  x86_64-darwin-17
118
126
  x86_64-darwin-19
127
+ x86_64-linux
119
128
 
120
129
  DEPENDENCIES
121
130
  cloudenvoy!
122
- grpc (~> 1.40.0)
123
- puma (~> 5.5.2)
131
+ puma (~> 5.6.4)
124
132
  rake
125
133
  sinatra
126
134
 
@@ -17,6 +17,10 @@ Cloudenvoy.setup_subscribers
17
17
  HelloPublisher.publish('Some message')
18
18
  ```
19
19
  8. Tail the logs to see how message get processed by `HelloSubscriber`
20
+ 9. Try sending multiple messages at once:
21
+ ```ruby
22
+ HelloPublisher.publish_all(['message1', 'message2', 'message3'])
23
+ ```
20
24
 
21
25
  ## Run using GCP Pub/Sub
22
26
 
@@ -11,6 +11,6 @@ class HelloSubscriber
11
11
  # @param [Cloudenvoy::Message] message The message to process.
12
12
  #
13
13
  def process(message)
14
- logger.info("Received message #{message.payload.dig('content')}")
14
+ logger.info("Received message #{message.payload['content']}")
15
15
  end
16
16
  end
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Force logging to be realtime
4
- STDOUT.sync = true
4
+ $stdout.sync = true
5
5
 
6
6
  # Require project files
7
7
  require 'sinatra'
8
- Dir.glob('./config/initializers/*.rb').each { |file| require file }
9
- Dir.glob('./app/publishers/*.rb').each { |file| require file }
10
- Dir.glob('./app/subscribers/*.rb').each { |file| require file }
8
+ Dir.glob('./config/initializers/*.rb').sort.each { |file| require file }
9
+ Dir.glob('./app/publishers/*.rb').sort.each { |file| require file }
10
+ Dir.glob('./app/subscribers/*.rb').sort.each { |file| require file }
11
11
 
12
12
  #---------------------------------------------------
13
13
  # Routes
@@ -54,7 +54,7 @@ module Cloudenvoy
54
54
  # @param [Hash, String] payload The message content.
55
55
  # @param [Hash] metadata The message attributes.
56
56
  #
57
- # @return [Cloudenvoy::Message] The created message.
57
+ # @return [Cloudenvoy::Message] The published message.
58
58
  #
59
59
  def publish(topic, payload, metadata = {})
60
60
  # Retrieve the topic
@@ -72,6 +72,38 @@ module Cloudenvoy
72
72
  )
73
73
  end
74
74
 
75
+ #
76
+ # Publish multiple messages to a topic.
77
+ #
78
+ # @param [String] topic The name of the topic
79
+ # @param [Array<Array<[Hash, String]>>] msg_args A list of message [payload, metadata].
80
+ #
81
+ # @return [Array<Cloudenvoy::Message>] The published messages.
82
+ #
83
+ def publish_all(topic, msg_args)
84
+ # Retrieve the topic
85
+ ps_topic = backend.topic(topic, skip_lookup: true)
86
+
87
+ # Publish the message
88
+ ps_msgs = ps_topic.publish do |batch|
89
+ msg_args.each do |(payload, metadata)|
90
+ batch.publish(payload.to_json, metadata.to_h)
91
+ end
92
+ end
93
+
94
+ # Return the formatted messages
95
+ ps_msgs.each_with_index.map do |ps_msg, index|
96
+ payload, metadata = msg_args[index]
97
+
98
+ Message.new(
99
+ id: ps_msg.message_id,
100
+ payload: payload,
101
+ metadata: metadata,
102
+ topic: topic
103
+ )
104
+ end
105
+ end
106
+
75
107
  #
76
108
  # Create or update a subscription for a specific topic.
77
109
  #
@@ -134,8 +166,8 @@ module Cloudenvoy
134
166
  def upsert_topic(topic)
135
167
  ps_topic = begin
136
168
  backend.create_topic(topic)
137
- rescue Google::Cloud::AlreadyExistsError
138
- backend.topic(topic)
169
+ rescue Google::Cloud::AlreadyExistsError
170
+ backend.topic(topic)
139
171
  end
140
172
 
141
173
  # Return formatted subscription
@@ -47,7 +47,7 @@ module Cloudenvoy
47
47
  # @param [Hash, String] payload The message content.
48
48
  # @param [Hash] attrs The message attributes.
49
49
  #
50
- # @return [Cloudenvoy::Message] The created message.
50
+ # @return [Cloudenvoy::Message] The published message.
51
51
  #
52
52
  def publish(topic, payload, metadata = {})
53
53
  msg = Message.new(
@@ -61,6 +61,30 @@ module Cloudenvoy
61
61
  msg
62
62
  end
63
63
 
64
+ #
65
+ # Publish multiple messages to a topic.
66
+ #
67
+ # @param [String] topic The name of the topic
68
+ # @param [Array<Array<[Hash, String]>>] msg_args A list of message [payload, metadata].
69
+ #
70
+ # @return [Array<Cloudenvoy::Message>] The published messages.
71
+ #
72
+ def publish_all(topic, msg_args)
73
+ # Build the messages
74
+ msgs = msg_args.map do |(payload, metadata)|
75
+ Message.new(
76
+ id: SecureRandom.uuid,
77
+ payload: payload,
78
+ metadata: metadata,
79
+ topic: topic
80
+ )
81
+ end
82
+
83
+ # Push all the messages and return them
84
+ queue(topic).push(*msgs)
85
+ msgs
86
+ end
87
+
64
88
  #
65
89
  # Create or update a subscription for a specific topic.
66
90
  #
@@ -57,7 +57,7 @@ module Cloudenvoy
57
57
  # @return [Logger, any] The cloudenvoy logger.
58
58
  #
59
59
  def logger
60
- @logger ||= defined?(Rails) ? Rails.logger : ::Logger.new(STDOUT)
60
+ @logger ||= defined?(Rails) ? Rails.logger : ::Logger.new($stdout)
61
61
  end
62
62
 
63
63
  #
@@ -75,8 +75,8 @@ module Cloudenvoy
75
75
  def to_h
76
76
  {
77
77
  id: id,
78
- payload: payload&.dup,
79
- metadata: metadata&.dup,
78
+ payload: payload.dup,
79
+ metadata: metadata.dup,
80
80
  topic: topic,
81
81
  sub_uri: sub_uri
82
82
  }.compact
@@ -30,12 +30,24 @@ module Cloudenvoy
30
30
  # @param [Hash, String] payload The message content.
31
31
  # @param [Hash] attrs The message attributes.
32
32
  #
33
- # @return [Cloudenvoy::Message] The created message.
33
+ # @return [Cloudenvoy::Message] The published message.
34
34
  #
35
35
  def self.publish(topic, payload, attrs = {})
36
36
  backend.publish(topic, payload, attrs)
37
37
  end
38
38
 
39
+ #
40
+ # Publish multiple messages to a topic.
41
+ #
42
+ # @param [String] topic The name of the topic
43
+ # @param [Array<Array<[Hash, String]>>] msg_args A list of message [payload, metadata].
44
+ #
45
+ # @return [Array<Cloudenvoy::Message>] The published messages.
46
+ #
47
+ def self.publish_all(topic, msg_args)
48
+ backend.publish_all(topic, msg_args)
49
+ end
50
+
39
51
  #
40
52
  # Create or update a subscription for a specific topic.
41
53
  #
@@ -89,6 +89,40 @@ module Cloudenvoy
89
89
 
90
90
  PubSubClient.upsert_topic(default_topic)
91
91
  end
92
+
93
+ #
94
+ # Publish all messages in one batch.
95
+ #
96
+ # @param [Array<Any>] The list of publisher arguments.
97
+ #
98
+ # @return [Array<Cloudenvoy::Message>] The published messages.
99
+ #
100
+ def publish_all(arg_list)
101
+ # Build the list of publishers
102
+ publishers = arg_list.map { |e| new(msg_args: [e].flatten(1)) }
103
+
104
+ # Batches are topic specific. We must send one batch of messages per topic.
105
+ publishers.group_by { |e| e.topic(*e.msg_args) }.map do |topic, topic_publishers|
106
+ # Chain publish calls. The very last call (when the chain becomes empty)
107
+ # is the actual batch publishing of messages to pub/sub
108
+ chain = topic_publishers.dup
109
+ traverse_chain = lambda do
110
+ if chain.empty?
111
+ # Send the messages in one batch and retrospectively attach them
112
+ # to each publisher
113
+ arg_list = topic_publishers.map { |e| [e.payload(*e.msg_args), e.metadata(*e.msg_args)] }
114
+ PubSubClient.publish_all(topic, arg_list).each_with_index do |msg, pub_index|
115
+ topic_publishers[pub_index].message = msg
116
+ end
117
+ else
118
+ # Defer message publishing to the next element
119
+ # in the chain until the chain is empty
120
+ chain.shift.publish(&traverse_chain)
121
+ end
122
+ end
123
+ traverse_chain.call
124
+ end.flatten
125
+ end
92
126
  end
93
127
 
94
128
  #
@@ -155,9 +189,9 @@ module Cloudenvoy
155
189
  #
156
190
  # @return [Cloudenvoy::Message] The created message.
157
191
  #
158
- def publish
192
+ def publish(&block)
159
193
  # Format and publish message
160
- resp = execute_middleware_chain
194
+ resp = execute_middleware_chain(&block)
161
195
 
162
196
  # Log job completion and return result
163
197
  logger.info("Published message in #{publishing_duration}s") { { duration: publishing_duration } }
@@ -191,14 +225,14 @@ module Cloudenvoy
191
225
  #
192
226
  # Execute the subscriber process method through the middleware chain.
193
227
  #
194
- # @return [Any] The result of the perform method.
228
+ # @return [Cloudenvoy::Message] The published message.
195
229
  #
196
- def execute_middleware_chain
230
+ def execute_middleware_chain(&block)
197
231
  self.publishing_started_at = Time.now
198
232
 
199
233
  Cloudenvoy.config.publisher_middleware.invoke(self) do
200
234
  begin
201
- publish_message
235
+ block_given? ? block.call : publish_message
202
236
  rescue StandardError => e
203
237
  logger.error([e, e.backtrace.join("\n")].join("\n"))
204
238
  try(:on_error, e)
@@ -9,7 +9,7 @@ module Cloudenvoy
9
9
  # @return [Proc] The context processor proc.
10
10
  #
11
11
  def self.default_context_processor
12
- @default_context_processor ||= ->(loggable) { loggable.message&.to_h&.slice(:id, :metadata, :topic) || {} }
12
+ @default_context_processor ||= ->(loggable) { loggable.message.to_h&.slice(:id, :metadata, :topic) || {} }
13
13
  end
14
14
 
15
15
  #
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Cloudenvoy
4
- VERSION = '0.5.rc1'
4
+ VERSION = '0.6.0'
5
5
  end
data/lib/cloudenvoy.rb CHANGED
@@ -63,6 +63,18 @@ module Cloudenvoy
63
63
  PubSubClient.publish(topic, payload, attrs)
64
64
  end
65
65
 
66
+ #
67
+ # Publish multiple messages to a topic. Shorthand method to Cloudenvoy::PubSubClient#publish_all.
68
+ #
69
+ # @param [String] topic The name of the topic
70
+ # @param [Array<Array<[Hash, String]>>] msg_args A list of message [payload, metadata].
71
+ #
72
+ # @return [Array<Cloudenvoy::Message>] The published messages.
73
+ #
74
+ def self.publish_all(topic, msg_args)
75
+ PubSubClient.publish_all(topic, msg_args)
76
+ end
77
+
66
78
  #
67
79
  # Return the list of registered publishers.
68
80
  #
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cloudenvoy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.rc1
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arnaud Lachaume
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-01-05 00:00:00.000000000 Z
11
+ date: 2022-07-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -114,14 +114,14 @@ dependencies:
114
114
  requirements:
115
115
  - - '='
116
116
  - !ruby/object:Gem::Version
117
- version: 0.76.0
117
+ version: 0.93.0
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - '='
123
123
  - !ruby/object:Gem::Version
124
- version: 0.76.0
124
+ version: 0.93.0
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: rubocop-rspec
127
127
  requirement: !ruby/object:Gem::Requirement
@@ -281,19 +281,13 @@ files:
281
281
  - examples/sinatra/config/initializers/cloudenvoy.rb
282
282
  - gemfiles/.bundle/config
283
283
  - gemfiles/rails_5.2.gemfile
284
- - gemfiles/rails_5.2.gemfile.lock
285
284
  - gemfiles/rails_6.0.gemfile
286
- - gemfiles/rails_6.0.gemfile.lock
287
285
  - gemfiles/rails_6.1.gemfile
288
286
  - gemfiles/rails_7.0.gemfile
289
287
  - gemfiles/semantic_logger_3.4.gemfile
290
- - gemfiles/semantic_logger_3.4.gemfile.lock
291
288
  - gemfiles/semantic_logger_4.6.gemfile
292
- - gemfiles/semantic_logger_4.6.gemfile.lock
293
289
  - gemfiles/semantic_logger_4.7.0.gemfile
294
- - gemfiles/semantic_logger_4.7.0.gemfile.lock
295
290
  - gemfiles/semantic_logger_4.7.2.gemfile
296
- - gemfiles/semantic_logger_4.7.2.gemfile.lock
297
291
  - lib/cloudenvoy.rb
298
292
  - lib/cloudenvoy/authentication_error.rb
299
293
  - lib/cloudenvoy/authenticator.rb
@@ -336,14 +330,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
336
330
  requirements:
337
331
  - - ">="
338
332
  - !ruby/object:Gem::Version
339
- version: 2.3.0
333
+ version: 2.4.0
340
334
  required_rubygems_version: !ruby/object:Gem::Requirement
341
335
  requirements:
342
- - - ">"
336
+ - - ">="
343
337
  - !ruby/object:Gem::Version
344
- version: 1.3.1
338
+ version: '0'
345
339
  requirements: []
346
- rubygems_version: 3.2.3
340
+ rubygems_version: 3.1.6
347
341
  signing_key:
348
342
  specification_version: 4
349
343
  summary: Cross-application messaging using GCP Pub/Sub (alpha)