google-cloud-pubsub 1.9.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 (58) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +18 -0
  3. data/AUTHENTICATION.md +177 -0
  4. data/CHANGELOG.md +538 -0
  5. data/CODE_OF_CONDUCT.md +40 -0
  6. data/CONTRIBUTING.md +188 -0
  7. data/EMULATOR.md +37 -0
  8. data/LICENSE +201 -0
  9. data/LOGGING.md +32 -0
  10. data/OVERVIEW.md +557 -0
  11. data/TROUBLESHOOTING.md +31 -0
  12. data/lib/google-cloud-pubsub.rb +139 -0
  13. data/lib/google/cloud/pubsub.rb +173 -0
  14. data/lib/google/cloud/pubsub/async_publisher.rb +399 -0
  15. data/lib/google/cloud/pubsub/async_publisher/batch.rb +309 -0
  16. data/lib/google/cloud/pubsub/batch_publisher.rb +99 -0
  17. data/lib/google/cloud/pubsub/convert.rb +91 -0
  18. data/lib/google/cloud/pubsub/credentials.rb +47 -0
  19. data/lib/google/cloud/pubsub/errors.rb +85 -0
  20. data/lib/google/cloud/pubsub/message.rb +158 -0
  21. data/lib/google/cloud/pubsub/policy.rb +187 -0
  22. data/lib/google/cloud/pubsub/project.rb +393 -0
  23. data/lib/google/cloud/pubsub/publish_result.rb +103 -0
  24. data/lib/google/cloud/pubsub/received_message.rb +297 -0
  25. data/lib/google/cloud/pubsub/retry_policy.rb +90 -0
  26. data/lib/google/cloud/pubsub/service.rb +514 -0
  27. data/lib/google/cloud/pubsub/snapshot.rb +202 -0
  28. data/lib/google/cloud/pubsub/snapshot/list.rb +178 -0
  29. data/lib/google/cloud/pubsub/subscriber.rb +399 -0
  30. data/lib/google/cloud/pubsub/subscriber/enumerator_queue.rb +54 -0
  31. data/lib/google/cloud/pubsub/subscriber/inventory.rb +166 -0
  32. data/lib/google/cloud/pubsub/subscriber/sequencer.rb +115 -0
  33. data/lib/google/cloud/pubsub/subscriber/stream.rb +401 -0
  34. data/lib/google/cloud/pubsub/subscriber/timed_unary_buffer.rb +231 -0
  35. data/lib/google/cloud/pubsub/subscription.rb +1279 -0
  36. data/lib/google/cloud/pubsub/subscription/list.rb +205 -0
  37. data/lib/google/cloud/pubsub/subscription/push_config.rb +244 -0
  38. data/lib/google/cloud/pubsub/topic.rb +934 -0
  39. data/lib/google/cloud/pubsub/topic/list.rb +171 -0
  40. data/lib/google/cloud/pubsub/v1.rb +17 -0
  41. data/lib/google/cloud/pubsub/v1/credentials.rb +41 -0
  42. data/lib/google/cloud/pubsub/v1/doc/google/iam/v1/iam_policy.rb +21 -0
  43. data/lib/google/cloud/pubsub/v1/doc/google/iam/v1/options.rb +21 -0
  44. data/lib/google/cloud/pubsub/v1/doc/google/iam/v1/policy.rb +21 -0
  45. data/lib/google/cloud/pubsub/v1/doc/google/protobuf/duration.rb +91 -0
  46. data/lib/google/cloud/pubsub/v1/doc/google/protobuf/empty.rb +29 -0
  47. data/lib/google/cloud/pubsub/v1/doc/google/protobuf/field_mask.rb +222 -0
  48. data/lib/google/cloud/pubsub/v1/doc/google/protobuf/timestamp.rb +113 -0
  49. data/lib/google/cloud/pubsub/v1/doc/google/pubsub/v1/pubsub.rb +833 -0
  50. data/lib/google/cloud/pubsub/v1/doc/google/type/expr.rb +19 -0
  51. data/lib/google/cloud/pubsub/v1/publisher_client.rb +928 -0
  52. data/lib/google/cloud/pubsub/v1/publisher_client_config.json +120 -0
  53. data/lib/google/cloud/pubsub/v1/subscriber_client.rb +1466 -0
  54. data/lib/google/cloud/pubsub/v1/subscriber_client_config.json +153 -0
  55. data/lib/google/cloud/pubsub/version.rb +24 -0
  56. data/lib/google/pubsub/v1/pubsub_pb.rb +269 -0
  57. data/lib/google/pubsub/v1/pubsub_services_pb.rb +215 -0
  58. metadata +337 -0
@@ -0,0 +1,309 @@
1
+ # Copyright 2019 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ require "monitor"
17
+ require "google/cloud/pubsub/errors"
18
+
19
+ module Google
20
+ module Cloud
21
+ module PubSub
22
+ class AsyncPublisher
23
+ ##
24
+ # @private
25
+ class Batch
26
+ include MonitorMixin
27
+
28
+ attr_reader :items, :ordering_key
29
+
30
+ def initialize publisher, ordering_key
31
+ # init MonitorMixin
32
+ super()
33
+
34
+ @publisher = publisher
35
+ @ordering_key = ordering_key
36
+ @items = []
37
+ @queue = []
38
+ @default_message_bytes = publisher.topic_name.bytesize + 2
39
+ @total_message_bytes = @default_message_bytes
40
+ @publishing = false
41
+ @stopping = false
42
+ @canceled = false
43
+ end
44
+
45
+ ##
46
+ # Adds a message and callback to the batch.
47
+ #
48
+ # The method will indicate how the message is added. It will either be
49
+ # added to the active list of items, it will be queued to be picked up
50
+ # once the active publishing job has been completed, or it will
51
+ # indicate that the batch is full and a publishing job should be
52
+ # created.
53
+ #
54
+ # @param [Google::Cloud::PubSub::V1::PubsubMessage] msg The message.
55
+ # @param [Proc, nil] callback The callback.
56
+ #
57
+ # @return [Symbol] The state of the batch.
58
+ #
59
+ # * `:added` - Added to the active list of items to be published.
60
+ # * `:queued` - Batch is publishing, and the messsage is queued.
61
+ # * `:full` - Batch is full and ready to be published, and the
62
+ # message is queued.
63
+ #
64
+ def add msg, callback
65
+ synchronize do
66
+ raise AsyncPublisherStopped if @stopping
67
+ raise OrderingKeyError, @ordering_key if @canceled
68
+
69
+ if @publishing
70
+ queue_add msg, callback
71
+ :queued
72
+ elsif try_add msg, callback
73
+ :added
74
+ else
75
+ queue_add msg, callback
76
+ :full
77
+ end
78
+ end
79
+ end
80
+
81
+ ##
82
+ # Marks the batch to be published.
83
+ #
84
+ # The method will indicate whether a new publishing job should be
85
+ # started to publish the batch. See {publishing?}.
86
+ #
87
+ # @param [Boolean] stop Indicates whether the batch should also be
88
+ # marked for stopping, and any existing publish job should publish
89
+ # all items until the batch is empty.
90
+ #
91
+ # @return [Boolean] Returns whether a new publishing job should be
92
+ # started to publish the batch. If the batch is already being
93
+ # published then this will return `false`.
94
+ #
95
+ def publish! stop: nil
96
+ synchronize do
97
+ @stopping = true if stop
98
+
99
+ return false if @canceled
100
+
101
+ # If we are already publishing, do not indicate a new job needs to
102
+ # be started.
103
+ return false if @publishing
104
+
105
+ @publishing = !(@items.empty? && @queue.empty?)
106
+ end
107
+ end
108
+
109
+ ##
110
+ # Indicates whether the batch has an active publishing job.
111
+ #
112
+ # @return [Boolean]
113
+ #
114
+ def publishing?
115
+ # This probably does not need to be synchronized
116
+ @publishing
117
+ end
118
+
119
+ ##
120
+ # Indicates whether the batch has been stopped and all items will be
121
+ # published until the batch is empty.
122
+ #
123
+ # @return [Boolean]
124
+ #
125
+ def stopping?
126
+ # This does not need to be synchronized because nothing un-stops
127
+ @stopping
128
+ end
129
+
130
+ ##
131
+ # Rebalances the batch by moving any queued items that will fit into
132
+ # the active item list.
133
+ #
134
+ # This method is only intended to be used by the active publishing
135
+ # job.
136
+ #
137
+ def rebalance!
138
+ synchronize do
139
+ return [] if @canceled
140
+
141
+ until @queue.empty?
142
+ item = @queue.first
143
+ if try_add item.msg, item.callback
144
+ @queue.shift
145
+ next
146
+ end
147
+ break
148
+ end
149
+
150
+ @items
151
+ end
152
+ end
153
+
154
+ # rubocop:disable Metrics/MethodLength
155
+
156
+ ##
157
+ # Resets the batch after a successful publish. This clears the active
158
+ # item list and moves the queued items that will fit into the active
159
+ # item list.
160
+ #
161
+ # If the batch has enough queued items to fill the batch again, the
162
+ # publishing job should continue to publish the reset batch until the
163
+ # batch indicated it should stop.
164
+ #
165
+ # This method is only intended to be used by the active publishing
166
+ # job.
167
+ #
168
+ # @return [Boolean] Whether the active publishing job should continue
169
+ # publishing after the reset.
170
+ #
171
+ def reset!
172
+ synchronize do
173
+ @items = []
174
+ @total_message_bytes = @default_message_bytes
175
+
176
+ if @canceled
177
+ @queue = []
178
+ @publishing = false
179
+ return false
180
+ end
181
+
182
+ until @queue.empty?
183
+ item = @queue.first
184
+ added = try_add item.msg, item.callback
185
+ break unless added
186
+ @queue.shift
187
+ end
188
+
189
+ return false unless @publishing
190
+ if @items.empty?
191
+ @publishing = false
192
+ return false
193
+ else
194
+ return true if stopping?
195
+ if @queue.empty?
196
+ @publishing = false
197
+ return false
198
+ end
199
+ end
200
+ end
201
+ true
202
+ end
203
+
204
+ # rubocop:enable Metrics/MethodLength
205
+
206
+ ##
207
+ # Cancel the batch and hault futher batches until resumed. See
208
+ # {#resume!} and {#canceled?}.
209
+ #
210
+ # @return [Array<Item}] All items, including queued items
211
+ #
212
+ def cancel!
213
+ synchronize do
214
+ @canceled = true
215
+ @items + @queue
216
+ end
217
+ end
218
+
219
+ ##
220
+ # Resume the batch and proceed to publish messages. See {#cancel!} and
221
+ # {#canceled?}.
222
+ #
223
+ # @return [Boolean] Whether the batch was resumed.
224
+ #
225
+ def resume!
226
+ synchronize do
227
+ # Return false if the batch is not canceled
228
+ return false unless @canceled
229
+
230
+ @items = []
231
+ @queue = []
232
+ @total_message_bytes = @default_message_bytes
233
+ @publishing = false
234
+ @canceled = false
235
+ end
236
+ true
237
+ end
238
+
239
+ ##
240
+ # Indicates whether the batch has been canceled due to an error while
241
+ # publishing. See {#cancel!} and {#resume!}.
242
+ #
243
+ # @return [Boolean]
244
+ #
245
+ def canceled?
246
+ # This does not need to be synchronized because nothing un-stops
247
+ synchronize { @canceled }
248
+ end
249
+
250
+ ##
251
+ # Determines whether the batch is empty and ready to be culled.
252
+ #
253
+ def empty?
254
+ synchronize do
255
+ return false if @publishing || @canceled || @stopping
256
+
257
+ @items.empty? && @queue.empty?
258
+ end
259
+ end
260
+
261
+ protected
262
+
263
+ def items_add msg, callback
264
+ item = Item.new msg, callback
265
+ @items << item
266
+ @total_message_bytes += item.bytesize + 2
267
+ end
268
+
269
+ def try_add msg, callback
270
+ if @items.empty?
271
+ # Always add when empty, even if bytesize is bigger than total
272
+ items_add msg, callback
273
+ return true
274
+ end
275
+ new_message_count = total_message_count + 1
276
+ new_message_bytes = total_message_bytes + msg.to_proto.bytesize + 2
277
+ if new_message_count > @publisher.max_messages ||
278
+ new_message_bytes >= @publisher.max_bytes
279
+ return false
280
+ end
281
+ items_add msg, callback
282
+ true
283
+ end
284
+
285
+ def queue_add msg, callback
286
+ item = Item.new msg, callback
287
+ @queue << item
288
+ end
289
+
290
+ def total_message_count
291
+ @items.count
292
+ end
293
+
294
+ def total_message_bytes
295
+ @total_message_bytes
296
+ end
297
+
298
+ Item = Struct.new :msg, :callback do
299
+ def bytesize
300
+ msg.to_proto.bytesize
301
+ end
302
+ end
303
+ end
304
+ end
305
+ end
306
+
307
+ Pubsub = PubSub unless const_defined? :Pubsub
308
+ end
309
+ end
@@ -0,0 +1,99 @@
1
+ # Copyright 2015 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ module Google
17
+ module Cloud
18
+ module PubSub
19
+ ##
20
+ # Topic Batch Publisher object used to publish multiple messages at
21
+ # once.
22
+ #
23
+ # @example
24
+ # require "google/cloud/pubsub"
25
+ #
26
+ # pubsub = Google::Cloud::PubSub.new
27
+ #
28
+ # topic = pubsub.topic "my-topic"
29
+ # msgs = topic.publish do |t|
30
+ # t.publish "task 1 completed", foo: :bar
31
+ # t.publish "task 2 completed", foo: :baz
32
+ # t.publish "task 3 completed", foo: :bif
33
+ # end
34
+ class BatchPublisher
35
+ ##
36
+ # @private The messages to publish
37
+ attr_reader :messages
38
+
39
+ ##
40
+ # @private Create a new instance of the object.
41
+ def initialize data = nil, attributes = {}
42
+ @messages = []
43
+ @mode = :batch
44
+ return if data.nil?
45
+ @mode = :single
46
+ publish data, attributes
47
+ end
48
+
49
+ ##
50
+ # Add a message to the batch to be published to the topic.
51
+ # All messages added to the batch will be published at once.
52
+ # See {Google::Cloud::PubSub::Topic#publish}
53
+ def publish data, attributes = {}
54
+ @messages << create_pubsub_message(data, attributes)
55
+ end
56
+
57
+ ##
58
+ # @private Create Message objects with message ids.
59
+ def to_gcloud_messages message_ids
60
+ msgs = @messages.zip(Array(message_ids)).map do |msg, id|
61
+ msg.message_id = id
62
+ Message.from_grpc msg
63
+ end
64
+ # Return just one Message if a single publish,
65
+ # otherwise return the array of Messages.
66
+ if @mode == :single && msgs.count <= 1
67
+ msgs.first
68
+ else
69
+ msgs
70
+ end
71
+ end
72
+
73
+ protected
74
+
75
+ def create_pubsub_message data, attributes
76
+ attributes ||= {}
77
+ if data.is_a?(::Hash) && attributes.empty?
78
+ attributes = data
79
+ data = nil
80
+ end
81
+ # Convert IO-ish objects to strings
82
+ if data.respond_to?(:read) && data.respond_to?(:rewind)
83
+ data.rewind
84
+ data = data.read
85
+ end
86
+ # Convert data to encoded byte array to match the protobuf defn
87
+ data_bytes = String(data).dup.force_encoding(Encoding::ASCII_8BIT).freeze
88
+
89
+ # Convert attributes to strings to match the protobuf definition
90
+ attributes = Hash[attributes.map { |k, v| [String(k), String(v)] }]
91
+
92
+ Google::Cloud::PubSub::V1::PubsubMessage.new data: data_bytes, attributes: attributes
93
+ end
94
+ end
95
+ end
96
+
97
+ Pubsub = PubSub unless const_defined? :Pubsub
98
+ end
99
+ end
@@ -0,0 +1,91 @@
1
+ # Copyright 2017 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ require "time"
17
+
18
+ module Google
19
+ module Cloud
20
+ module PubSub
21
+ ##
22
+ # @private Helper module for converting Pub/Sub values.
23
+ module Convert
24
+ module ClassMethods
25
+ def time_to_timestamp time
26
+ return nil if time.nil?
27
+
28
+ # Force the object to be a Time object.
29
+ time = time.to_time
30
+
31
+ Google::Protobuf::Timestamp.new seconds: time.to_i, nanos: time.nsec
32
+ end
33
+
34
+ def timestamp_to_time timestamp
35
+ return nil if timestamp.nil?
36
+
37
+ Time.at timestamp.seconds, Rational(timestamp.nanos, 1000)
38
+ end
39
+
40
+ def number_to_duration number
41
+ return nil if number.nil?
42
+
43
+ Google::Protobuf::Duration.new seconds: number.to_i, nanos: (number.remainder(1) * 1_000_000_000).round
44
+ end
45
+
46
+ def duration_to_number duration
47
+ return nil if duration.nil?
48
+
49
+ return duration.seconds if duration.nanos.zero?
50
+
51
+ duration.seconds + (duration.nanos / 1_000_000_000.0)
52
+ end
53
+
54
+ def pubsub_message data, attributes, ordering_key, extra_attrs
55
+ # TODO: allow data to be a Message object,
56
+ # then ensure attributes and ordering_key are nil
57
+ if data.is_a?(::Hash) && (attributes.nil? || attributes.empty?)
58
+ attributes = data.merge extra_attrs
59
+ data = nil
60
+ else
61
+ attributes = Hash(attributes).merge extra_attrs
62
+ end
63
+ # Convert IO-ish objects to strings
64
+ if data.respond_to?(:read) && data.respond_to?(:rewind)
65
+ data.rewind
66
+ data = data.read
67
+ end
68
+ # Convert data to encoded byte array to match the protobuf defn
69
+ data_bytes = String(data).dup.force_encoding(Encoding::ASCII_8BIT).freeze
70
+
71
+ # Convert attributes to strings to match the protobuf definition
72
+ attributes = Hash[attributes.map { |k, v| [String(k), String(v)] }]
73
+
74
+ # Ordering Key must always be a string
75
+ ordering_key = String(ordering_key).freeze
76
+
77
+ Google::Cloud::PubSub::V1::PubsubMessage.new(
78
+ data: data_bytes,
79
+ attributes: attributes,
80
+ ordering_key: ordering_key
81
+ )
82
+ end
83
+ end
84
+
85
+ extend ClassMethods
86
+ end
87
+ end
88
+
89
+ Pubsub = PubSub unless const_defined? :Pubsub
90
+ end
91
+ end