google-cloud-pubsub 0.26.0 → 0.27.0

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