google-cloud-pubsub 0.26.0 → 0.27.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.
@@ -13,10 +13,12 @@
13
13
  # limitations under the License.
14
14
 
15
15
 
16
+ require "google/cloud/pubsub/convert"
16
17
  require "google/cloud/errors"
17
18
  require "google/cloud/pubsub/subscription/list"
18
19
  require "google/cloud/pubsub/received_message"
19
20
  require "google/cloud/pubsub/snapshot"
21
+ require "google/cloud/pubsub/subscriber"
20
22
 
21
23
  module Google
22
24
  module Cloud
@@ -49,26 +51,15 @@ module Google
49
51
  # @private Create an empty {Subscription} object.
50
52
  def initialize
51
53
  @service = nil
52
- @grpc = Google::Pubsub::V1::Subscription.new
53
- @name = nil
54
+ @grpc = nil
55
+ @lazy = nil
54
56
  @exists = nil
55
57
  end
56
58
 
57
- ##
58
- # @private New lazy {Topic} object without making an HTTP request.
59
- def self.new_lazy name, service, options = {}
60
- new.tap do |s|
61
- s.grpc = nil
62
- s.service = service
63
- s.instance_variable_set "@name",
64
- service.subscription_path(name, options)
65
- end
66
- end
67
-
68
59
  ##
69
60
  # The name of the subscription.
70
61
  def name
71
- @grpc ? @grpc.name : @name
62
+ @grpc.name
72
63
  end
73
64
 
74
65
  ##
@@ -98,6 +89,15 @@ module Google
98
89
  @grpc.ack_deadline_seconds
99
90
  end
100
91
 
92
+ def deadline= new_deadline
93
+ update_grpc = @grpc.dup
94
+ update_grpc.ack_deadline_seconds = new_deadline
95
+ @grpc = service.update_subscription update_grpc,
96
+ :ack_deadline_seconds
97
+ @lazy = nil
98
+ self
99
+ end
100
+
101
101
  ##
102
102
  # Indicates whether to retain acknowledged messages. If `true`, then
103
103
  # messages are not expunged from the subscription's backlog, even if
@@ -112,6 +112,15 @@ module Google
112
112
  @grpc.retain_acked_messages
113
113
  end
114
114
 
115
+ def retain_acked= new_retain_acked
116
+ update_grpc = @grpc.dup
117
+ update_grpc.retain_acked_messages = !(!new_retain_acked)
118
+ @grpc = service.update_subscription update_grpc,
119
+ :retain_acked_messages
120
+ @lazy = nil
121
+ self
122
+ end
123
+
115
124
  ##
116
125
  # How long to retain unacknowledged messages in the subscription's
117
126
  # backlog, from the moment a message is published. If
@@ -125,7 +134,17 @@ module Google
125
134
  #
126
135
  def retention
127
136
  ensure_grpc!
128
- duration_to_number @grpc.message_retention_duration
137
+ Convert.duration_to_number @grpc.message_retention_duration
138
+ end
139
+
140
+ def retention= new_retention
141
+ update_grpc = @grpc.dup
142
+ update_grpc.message_retention_duration = \
143
+ Convert.number_to_duration new_retention
144
+ @grpc = service.update_subscription update_grpc,
145
+ :message_retention_duration
146
+ @lazy = nil
147
+ self
129
148
  end
130
149
 
131
150
  ##
@@ -159,12 +178,12 @@ module Google
159
178
  # sub.exists? #=> true
160
179
  #
161
180
  def exists?
162
- # Always true if we have a grpc object
163
- return true unless @grpc.nil?
181
+ # Always true if the object is not set as lazy
182
+ return true unless lazy?
164
183
  # If we have a value, return it
165
184
  return @exists unless @exists.nil?
166
185
  ensure_grpc!
167
- @exists = !@grpc.nil?
186
+ @exists = true
168
187
  rescue Google::Cloud::NotFoundError
169
188
  @exists = false
170
189
  end
@@ -180,10 +199,10 @@ module Google
180
199
  # pubsub = Google::Cloud::Pubsub.new
181
200
  #
182
201
  # sub = pubsub.get_subscription "my-topic-sub"
183
- # sub.lazy? #=> false
202
+ # sub.lazy? #=> nil
184
203
  #
185
204
  def lazy?
186
- @grpc.nil?
205
+ @lazy
187
206
  end
188
207
 
189
208
  ##
@@ -220,8 +239,6 @@ module Google
220
239
  # @param [Integer] max The maximum number of messages to return for this
221
240
  # request. The Pub/Sub system may return fewer than the number
222
241
  # specified. The default value is `100`, the maximum value is `1000`.
223
- # @param [Boolean] autoack Automatically acknowledge the message as it
224
- # is pulled. The default value is `false`.
225
242
  #
226
243
  # @return [Array<Google::Cloud::Pubsub::ReceivedMessage>]
227
244
  #
@@ -250,15 +267,13 @@ module Google
250
267
  # msgs = sub.pull immediate: false
251
268
  # msgs.each { |msg| msg.acknowledge! }
252
269
  #
253
- def pull immediate: true, max: 100, autoack: false
270
+ def pull immediate: true, max: 100
254
271
  ensure_service!
255
272
  options = { immediate: immediate, max: max }
256
273
  list_grpc = service.pull name, options
257
- messages = Array(list_grpc.received_messages).map do |msg_grpc|
274
+ Array(list_grpc.received_messages).map do |msg_grpc|
258
275
  ReceivedMessage.from_grpc msg_grpc, self
259
276
  end
260
- acknowledge messages if autoack
261
- messages
262
277
  rescue Google::Cloud::DeadlineExceededError
263
278
  []
264
279
  end
@@ -272,8 +287,6 @@ module Google
272
287
  # @param [Integer] max The maximum number of messages to return for this
273
288
  # request. The Pub/Sub system may return fewer than the number
274
289
  # specified. The default value is `100`, the maximum value is `1000`.
275
- # @param [Boolean] autoack Automatically acknowledge the message as it
276
- # is pulled. The default value is `false`.
277
290
  #
278
291
  # @return [Array<Google::Cloud::Pubsub::ReceivedMessage>]
279
292
  #
@@ -286,65 +299,79 @@ module Google
286
299
  # msgs = sub.wait_for_messages
287
300
  # msgs.each { |msg| msg.acknowledge! }
288
301
  #
289
- def wait_for_messages max: 100, autoack: false
290
- pull immediate: false, max: max, autoack: autoack
302
+ def wait_for_messages max: 100
303
+ pull immediate: false, max: max
291
304
  end
292
305
 
293
306
  ##
294
- # Poll the backend for new messages. This runs a loop to ping the API,
295
- # blocking indefinitely, yielding retrieved messages as they are
296
- # received.
307
+ # Create a {Subscriber} object that receives and processes messages
308
+ # using the code provided in the callback.
309
+ #
310
+ # @param [Numeric] deadline The default number of seconds the stream
311
+ # will hold received messages before modifying the message's ack
312
+ # deadline. The minimum is 10, the maximum is 600. Default is
313
+ # {#deadline}. Optional.
314
+ # @param [Integer] streams The number of concurrent streams to open to
315
+ # pull messages from the subscription. Default is 4. Optional.
316
+ # @param [Integer] inventory The number of received messages to be
317
+ # collected by subscriber. Default is 1,000. Optional.
318
+ # @param [Hash] threads The number of threads to create to handle
319
+ # concurrent calls by each stream opened by the subscriber. Optional.
320
+ #
321
+ # Hash keys and values may include the following:
322
+ #
323
+ # * `:callback` (Integer) The number of threads used to handle the
324
+ # received messages. Default is 8.
325
+ # * `:push` (Integer) The number of threads to handle
326
+ # acknowledgement ({ReceivedMessage#ack!}) and delay messages
327
+ # ({ReceivedMessage#nack!}, {ReceivedMessage#delay!}). Default is
328
+ # 4.
297
329
  #
298
- # @param [Integer] max The maximum number of messages to return for this
299
- # request. The Pub/Sub system may return fewer than the number
300
- # specified. The default value is `100`, the maximum value is `1000`.
301
- # @param [Boolean] autoack Automatically acknowledge the message as it
302
- # is pulled. The default value is `false`.
303
- # @param [Number] delay The number of seconds to pause between requests
304
- # when the Google Cloud service has no messages to return. The default
305
- # value is `1`.
306
330
  # @yield [msg] a block for processing new messages
307
331
  # @yieldparam [ReceivedMessage] msg the newly received message
308
332
  #
333
+ # @return [Subscriber]
334
+ #
309
335
  # @example
310
336
  # require "google/cloud/pubsub"
311
337
  #
312
338
  # pubsub = Google::Cloud::Pubsub.new
313
339
  #
314
340
  # sub = pubsub.subscription "my-topic-sub"
315
- # sub.listen do |msg|
341
+ #
342
+ # subscriber = sub.listen do |msg|
316
343
  # # process msg
344
+ # msg.ack!
317
345
  # end
318
346
  #
319
- # @example Limit number of messages pulled per API request with `max`:
320
- # require "google/cloud/pubsub"
347
+ # subscriber.start
321
348
  #
322
- # pubsub = Google::Cloud::Pubsub.new
349
+ # # Shut down the subscriber when ready to stop receiving messages.
350
+ # subscriber.stop.wait!
323
351
  #
324
- # sub = pubsub.subscription "my-topic-sub"
325
- # sub.listen max: 20 do |msg|
326
- # # process msg
327
- # end
328
- #
329
- # @example Automatically acknowledge messages with `autoack`:
352
+ # @example Configuring to increase concurrent callbacks:
330
353
  # require "google/cloud/pubsub"
331
354
  #
332
355
  # pubsub = Google::Cloud::Pubsub.new
333
356
  #
334
357
  # sub = pubsub.subscription "my-topic-sub"
335
- # sub.listen autoack: true do |msg|
336
- # # process msg
358
+ #
359
+ # subscriber = sub.listen threads: { callback: 16 } do |msg|
360
+ # # store the message somewhere before acknowledging
361
+ # store_in_backend msg.data # takes a few seconds
362
+ # msg.ack!
337
363
  # end
338
364
  #
339
- def listen max: 100, autoack: false, delay: 1
340
- loop do
341
- msgs = wait_for_messages max: max, autoack: autoack
342
- if msgs.any?
343
- msgs.each { |msg| yield msg }
344
- else
345
- sleep delay
346
- end
347
- end
365
+ # subscriber.start
366
+ #
367
+ def listen deadline: nil, streams: nil, inventory: nil, threads: {},
368
+ &block
369
+ ensure_service!
370
+ deadline ||= self.deadline
371
+
372
+ Subscriber.new name, block, deadline: deadline, streams: streams,
373
+ inventory: inventory, threads: threads,
374
+ service: service
348
375
  end
349
376
 
350
377
  ##
@@ -406,6 +433,7 @@ module Google
406
433
  service.modify_ack_deadline name, ack_ids, new_deadline
407
434
  true
408
435
  end
436
+ alias_method :modify_ack_deadline, :delay
409
437
 
410
438
  ##
411
439
  # Creates a new {Snapshot} from the subscription. The created snapshot
@@ -633,16 +661,18 @@ module Google
633
661
  end
634
662
  end
635
663
 
636
- protected
637
-
638
- def duration_to_number duration
639
- return nil if duration.nil?
640
-
641
- return duration.seconds if duration.nanos == 0
642
-
643
- duration.seconds + (duration.nanos / 1000000000.0)
664
+ ##
665
+ # @private New lazy {Topic} object without making an HTTP request.
666
+ def self.new_lazy name, service, options = {}
667
+ lazy_grpc = Google::Pubsub::V1::Subscription.new \
668
+ name: service.subscription_path(name, options)
669
+ from_grpc(lazy_grpc, service).tap do |s|
670
+ s.instance_variable_set :@lazy, true
671
+ end
644
672
  end
645
673
 
674
+ protected
675
+
646
676
  ##
647
677
  # @private Raise an error unless an active connection to the service is
648
678
  # available.
@@ -654,8 +684,8 @@ module Google
654
684
  # Ensures a Google::Pubsub::V1::Subscription object exists.
655
685
  def ensure_grpc!
656
686
  ensure_service!
657
- return @grpc if @grpc
658
- @grpc = service.get_subscription @name
687
+ @grpc = service.get_subscription name if lazy?
688
+ @lazy = nil
659
689
  end
660
690
 
661
691
  ##
@@ -14,8 +14,9 @@
14
14
 
15
15
 
16
16
  require "google/cloud/errors"
17
- require "google/cloud/pubsub/topic/publisher"
18
17
  require "google/cloud/pubsub/topic/list"
18
+ require "google/cloud/pubsub/async_publisher"
19
+ require "google/cloud/pubsub/batch_publisher"
19
20
  require "google/cloud/pubsub/subscription"
20
21
  require "google/cloud/pubsub/policy"
21
22
 
@@ -48,26 +49,43 @@ module Google
48
49
  # @private Create an empty {Topic} object.
49
50
  def initialize
50
51
  @service = nil
51
- @grpc = Google::Pubsub::V1::Topic.new
52
- @name = nil
52
+ @grpc = nil
53
+ @lazy = nil
53
54
  @exists = nil
55
+ @async_opts = {}
54
56
  end
55
57
 
56
58
  ##
57
- # @private New lazy {Topic} object without making an HTTP request.
58
- def self.new_lazy name, service, options = {}
59
- new.tap do |t|
60
- t.grpc = nil
61
- t.service = service
62
- t.instance_variable_set "@name", service.topic_path(name, options)
63
- end
59
+ # AsyncPublisher object used to publish multiple messages in batches.
60
+ #
61
+ # @return [AsyncPublisher] Returns publisher object if calls to
62
+ # {#publish_async} have been made, returns `nil` otherwise.
63
+ #
64
+ # @example
65
+ # require "google/cloud/pubsub"
66
+ #
67
+ # pubsub = Google::Cloud::Pubsub.new
68
+ #
69
+ # topic = pubsub.topic "my-topic"
70
+ # topic.publish_async "task completed" do |result|
71
+ # if result.succeeded?
72
+ # log_publish_success result.data
73
+ # else
74
+ # log_publish_failure result.data, result.error
75
+ # end
76
+ # end
77
+ #
78
+ # topic.async_publisher.stop.wait!
79
+ #
80
+ def async_publisher
81
+ @async_publisher
64
82
  end
65
83
 
66
84
  ##
67
85
  # The name of the topic in the form of
68
86
  # "/projects/project-identifier/topics/topic-name".
69
87
  def name
70
- @grpc ? @grpc.name : @name
88
+ @grpc.name
71
89
  end
72
90
 
73
91
  ##
@@ -234,11 +252,16 @@ module Google
234
252
  ##
235
253
  # Publishes one or more messages to the topic.
236
254
  #
237
- # @param [String, File] data The message data.
255
+ # The message payload must not be empty; it must contain either a
256
+ # non-empty data field, or at least one attribute.
257
+ #
258
+ # @param [String, File] data The message payload. This will be converted
259
+ # to bytes encoded as ASCII-8BIT.
238
260
  # @param [Hash] attributes Optional attributes for the message.
239
- # @yield [publisher] a block for publishing multiple messages in one
261
+ # @yield [batch] a block for publishing multiple messages in one
240
262
  # request
241
- # @yieldparam [Topic::Publisher] publisher the topic publisher object
263
+ # @yieldparam [BatchPublisher] batch the topic batch publisher
264
+ # object
242
265
  #
243
266
  # @return [Message, Array<Message>] Returns the published message when
244
267
  # called without a block, or an array of messages when called with a
@@ -258,7 +281,8 @@ module Google
258
281
  # pubsub = Google::Cloud::Pubsub.new
259
282
  #
260
283
  # topic = pubsub.topic "my-topic"
261
- # msg = topic.publish File.open("message.txt")
284
+ # file = File.open "message.txt", mode: "rb"
285
+ # msg = topic.publish file
262
286
  #
263
287
  # @example Additionally, a message can be published with attributes:
264
288
  # require "google/cloud/pubsub"
@@ -284,10 +308,68 @@ module Google
284
308
  #
285
309
  def publish data = nil, attributes = {}
286
310
  ensure_service!
287
- publisher = Publisher.new data, attributes
288
- yield publisher if block_given?
289
- return nil if publisher.messages.count.zero?
290
- publish_batch_messages publisher
311
+ batch = BatchPublisher.new data, attributes
312
+ yield batch if block_given?
313
+ return nil if batch.messages.count.zero?
314
+ publish_batch_messages batch
315
+ end
316
+
317
+ ##
318
+ # Publishes a message asynchonously to the topic.
319
+ #
320
+ # The message payload must not be empty; it must contain either a
321
+ # non-empty data field, or at least one attribute.
322
+ #
323
+ # @param [String, File] data The message payload. This will be converted
324
+ # to bytes encoded as ASCII-8BIT.
325
+ # @param [Hash] attributes Optional attributes for the message.
326
+ # @yield [result] the callback for when the message has been published
327
+ # @yieldparam [PublishResult] result the result of the asynchonous
328
+ # publish
329
+ #
330
+ # @example
331
+ # require "google/cloud/pubsub"
332
+ #
333
+ # pubsub = Google::Cloud::Pubsub.new
334
+ #
335
+ # topic = pubsub.topic "my-topic"
336
+ # topic.publish_async "task completed" do |result|
337
+ # if result.succeeded?
338
+ # log_publish_success result.data
339
+ # else
340
+ # log_publish_failure result.data, result.error
341
+ # end
342
+ # end
343
+ #
344
+ # topic.async_publisher.stop.wait!
345
+ #
346
+ # @example A message can be published using a File object:
347
+ # require "google/cloud/pubsub"
348
+ #
349
+ # pubsub = Google::Cloud::Pubsub.new
350
+ #
351
+ # topic = pubsub.topic "my-topic"
352
+ # file = File.open "message.txt", mode: "rb"
353
+ # topic.publish_async file
354
+ #
355
+ # topic.async_publisher.stop.wait!
356
+ #
357
+ # @example Additionally, a message can be published with attributes:
358
+ # require "google/cloud/pubsub"
359
+ #
360
+ # pubsub = Google::Cloud::Pubsub.new
361
+ #
362
+ # topic = pubsub.topic "my-topic"
363
+ # topic.publish_async "task completed",
364
+ # foo: :bar, this: :that
365
+ #
366
+ # topic.async_publisher.stop.wait!
367
+ #
368
+ def publish_async data = nil, attributes = {}, &block
369
+ ensure_service!
370
+
371
+ @async_publisher ||= AsyncPublisher.new(name, service, @async_opts)
372
+ @async_publisher.publish data, attributes, &block
291
373
  end
292
374
 
293
375
  ##
@@ -421,12 +503,14 @@ module Google
421
503
  # topic.exists? #=> true
422
504
  #
423
505
  def exists?
424
- # Always true if we have a grpc object
425
- return true unless @grpc.nil?
506
+ # Always true if the object is not set as lazy
507
+ return true unless lazy?
426
508
  # If we have a value, return it
427
509
  return @exists unless @exists.nil?
428
510
  ensure_grpc!
429
- @exists = !@grpc.nil?
511
+ @exists = true
512
+ rescue Google::Cloud::NotFoundError
513
+ @exists = false
430
514
  end
431
515
 
432
516
  ##
@@ -439,18 +523,29 @@ module Google
439
523
  # pubsub = Google::Cloud::Pubsub.new
440
524
  #
441
525
  # topic = pubsub.topic "my-topic"
442
- # topic.lazy? #=> false
526
+ # topic.lazy? #=> nil
443
527
  #
444
528
  def lazy?
445
- @grpc.nil?
529
+ @lazy
446
530
  end
447
531
 
448
532
  ##
449
533
  # @private New Topic from a Google::Pubsub::V1::Topic object.
450
- def self.from_grpc grpc, service
451
- new.tap do |f|
452
- f.grpc = grpc
453
- f.service = service
534
+ def self.from_grpc grpc, service, async: nil
535
+ new.tap do |t|
536
+ t.grpc = grpc
537
+ t.service = service
538
+ t.instance_variable_set :@async_opts, async if async
539
+ end
540
+ end
541
+
542
+ ##
543
+ # @private New lazy {Topic} object without making an HTTP request.
544
+ def self.new_lazy name, service, options = {}
545
+ lazy_grpc = Google::Pubsub::V1::Topic.new \
546
+ name: service.topic_path(name, options)
547
+ from_grpc(lazy_grpc, service).tap do |t|
548
+ t.instance_variable_set :@lazy, true
454
549
  end
455
550
  end
456
551
 
@@ -467,10 +562,8 @@ module Google
467
562
  # Ensures a Google::Pubsub::V1::Topic object exists.
468
563
  def ensure_grpc!
469
564
  ensure_service!
470
- return @grpc if @grpc
471
- @grpc = service.get_topic @name
472
- rescue Google::Cloud::NotFoundError
473
- nil
565
+ @grpc = service.get_topic name if lazy?
566
+ @lazy = nil
474
567
  end
475
568
 
476
569
  ##