cloudenvoy 0.5.rc1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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)