google-cloud-pubsub 0.20.0 → 2.6.1

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 (49) hide show
  1. checksums.yaml +5 -5
  2. data/.yardopts +18 -0
  3. data/AUTHENTICATION.md +178 -0
  4. data/CHANGELOG.md +659 -0
  5. data/CODE_OF_CONDUCT.md +40 -0
  6. data/CONTRIBUTING.md +187 -0
  7. data/EMULATOR.md +37 -0
  8. data/LICENSE +201 -0
  9. data/LOGGING.md +32 -0
  10. data/OVERVIEW.md +528 -0
  11. data/TROUBLESHOOTING.md +31 -0
  12. data/lib/google/cloud/pubsub/async_publisher/batch.rb +310 -0
  13. data/lib/google/cloud/pubsub/async_publisher.rb +402 -0
  14. data/lib/google/cloud/pubsub/batch_publisher.rb +100 -0
  15. data/lib/google/cloud/pubsub/convert.rb +91 -0
  16. data/lib/google/cloud/pubsub/credentials.rb +26 -10
  17. data/lib/google/cloud/pubsub/errors.rb +85 -0
  18. data/lib/google/cloud/pubsub/message.rb +82 -20
  19. data/lib/google/cloud/pubsub/policy.rb +40 -61
  20. data/lib/google/cloud/pubsub/project.rb +405 -265
  21. data/lib/google/cloud/pubsub/publish_result.rb +103 -0
  22. data/lib/google/cloud/pubsub/received_message.rb +165 -30
  23. data/lib/google/cloud/pubsub/retry_policy.rb +88 -0
  24. data/lib/google/cloud/pubsub/schema/list.rb +180 -0
  25. data/lib/google/cloud/pubsub/schema.rb +310 -0
  26. data/lib/google/cloud/pubsub/service.rb +304 -162
  27. data/lib/google/cloud/pubsub/snapshot/list.rb +178 -0
  28. data/lib/google/cloud/pubsub/snapshot.rb +205 -0
  29. data/lib/google/cloud/pubsub/subscriber/enumerator_queue.rb +54 -0
  30. data/lib/google/cloud/pubsub/subscriber/inventory.rb +173 -0
  31. data/lib/google/cloud/pubsub/subscriber/sequencer.rb +115 -0
  32. data/lib/google/cloud/pubsub/subscriber/stream.rb +400 -0
  33. data/lib/google/cloud/pubsub/subscriber/timed_unary_buffer.rb +230 -0
  34. data/lib/google/cloud/pubsub/subscriber.rb +417 -0
  35. data/lib/google/cloud/pubsub/subscription/list.rb +38 -43
  36. data/lib/google/cloud/pubsub/subscription/push_config.rb +268 -0
  37. data/lib/google/cloud/pubsub/subscription.rb +1040 -210
  38. data/lib/google/cloud/pubsub/topic/list.rb +32 -37
  39. data/lib/google/cloud/pubsub/topic.rb +726 -177
  40. data/lib/google/cloud/pubsub/version.rb +6 -4
  41. data/lib/google/cloud/pubsub.rb +138 -413
  42. data/lib/google-cloud-pubsub.rb +60 -42
  43. metadata +88 -39
  44. data/lib/google/cloud/pubsub/topic/publisher.rb +0 -87
  45. data/lib/google/iam/v1/iam_policy.rb +0 -33
  46. data/lib/google/iam/v1/iam_policy_services.rb +0 -30
  47. data/lib/google/iam/v1/policy.rb +0 -25
  48. data/lib/google/pubsub/v1/pubsub_pb.rb +0 -129
  49. data/lib/google/pubsub/v1/pubsub_services_pb.rb +0 -117
@@ -1,10 +1,10 @@
1
- # Copyright 2015 Google Inc. All rights reserved.
1
+ # Copyright 2015 Google LLC
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
5
5
  # You may obtain a copy of the License at
6
6
  #
7
- # http://www.apache.org/licenses/LICENSE-2.0
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
8
  #
9
9
  # Unless required by applicable law or agreed to in writing, software
10
10
  # distributed under the License is distributed on an "AS IS" BASIS,
@@ -13,13 +13,19 @@
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"
19
+ require "google/cloud/pubsub/subscription/push_config"
18
20
  require "google/cloud/pubsub/received_message"
21
+ require "google/cloud/pubsub/retry_policy"
22
+ require "google/cloud/pubsub/snapshot"
23
+ require "google/cloud/pubsub/subscriber"
24
+ require "google/cloud/pubsub/v1"
19
25
 
20
26
  module Google
21
27
  module Cloud
22
- module Pubsub
28
+ module PubSub
23
29
  ##
24
30
  # # Subscription
25
31
  #
@@ -27,215 +33,766 @@ module Google
27
33
  # specific {Topic}, to be delivered to the subscribing application.
28
34
  #
29
35
  # @example
30
- # require "google/cloud"
36
+ # require "google/cloud/pubsub"
31
37
  #
32
- # gcloud = Google::Cloud.new
33
- # pubsub = gcloud.pubsub
38
+ # pubsub = Google::Cloud::PubSub.new
34
39
  #
35
40
  # sub = pubsub.subscription "my-topic-sub"
36
- # msgs = sub.pull
37
- # msgs.each { |msg| msg.acknowledge! }
41
+ # subscriber = sub.listen do |received_message|
42
+ # # process message
43
+ # received_message.acknowledge!
44
+ # end
38
45
  #
46
+ # # Handle exceptions from listener
47
+ # subscriber.on_error do |exception|
48
+ # puts "Exception: #{exception.class} #{exception.message}"
49
+ # end
50
+ #
51
+ # # Gracefully shut down the subscriber
52
+ # at_exit do
53
+ # subscriber.stop!
54
+ # end
55
+ #
56
+ # # Start background threads that will call the block passed to listen.
57
+ # subscriber.start
58
+ # sleep
39
59
  class Subscription
40
60
  ##
41
- # @private The gRPC Service object.
61
+ # @private The Service object.
42
62
  attr_accessor :service
43
63
 
44
64
  ##
45
- # @private The gRPC Google::Pubsub::V1::Subscription object.
65
+ # @private The gRPC Google::Cloud::PubSub::V1::Subscription object.
46
66
  attr_accessor :grpc
47
67
 
48
68
  ##
49
69
  # @private Create an empty {Subscription} object.
50
70
  def initialize
51
71
  @service = nil
52
- @grpc = Google::Pubsub::V1::Subscription.new
53
- @name = nil
72
+ @grpc = nil
73
+ @resource_name = nil
54
74
  @exists = nil
55
75
  end
56
76
 
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
77
  ##
69
78
  # The name of the subscription.
79
+ #
80
+ # @return [String] A fully-qualified subscription name in the form
81
+ # `projects/{project_id}/subscriptions/{subscription_id}`.
82
+ #
70
83
  def name
71
- @grpc ? @grpc.name : @name
84
+ return @resource_name if reference?
85
+ @grpc.name
72
86
  end
73
87
 
74
88
  ##
75
89
  # The {Topic} from which this subscription receives messages.
76
90
  #
91
+ # Makes an API call to retrieve the topic information when called on a
92
+ # reference object. See {#reference?}.
93
+ #
77
94
  # @return [Topic]
78
95
  #
79
96
  # @example
80
- # require "google/cloud"
97
+ # require "google/cloud/pubsub"
81
98
  #
82
- # gcloud = Google::Cloud.new
83
- # pubsub = gcloud.pubsub
99
+ # pubsub = Google::Cloud::PubSub.new
84
100
  #
85
101
  # sub = pubsub.subscription "my-topic-sub"
86
102
  # sub.topic.name #=> "projects/my-project/topics/my-topic"
87
103
  #
88
104
  def topic
89
105
  ensure_grpc!
90
- Topic.new_lazy @grpc.topic, service
106
+ Topic.from_name @grpc.topic, service
91
107
  end
92
108
 
93
109
  ##
94
110
  # This value is the maximum number of seconds after a subscriber
95
111
  # receives a message before the subscriber should acknowledge the
96
112
  # message.
113
+ #
114
+ # Makes an API call to retrieve the deadline value when called on a
115
+ # reference object. See {#reference?}.
116
+ #
117
+ # @return [Integer]
97
118
  def deadline
98
119
  ensure_grpc!
99
120
  @grpc.ack_deadline_seconds
100
121
  end
101
122
 
123
+ ##
124
+ # Sets the maximum number of seconds after a subscriber
125
+ # receives a message before the subscriber should acknowledge the
126
+ # message.
127
+ #
128
+ # @param [Integer] new_deadline The new deadline value.
129
+ #
130
+ def deadline= new_deadline
131
+ update_grpc = Google::Cloud::PubSub::V1::Subscription.new name: name, ack_deadline_seconds: new_deadline
132
+ @grpc = service.update_subscription update_grpc, :ack_deadline_seconds
133
+ @resource_name = nil
134
+ end
135
+
136
+ ##
137
+ # Indicates whether to retain acknowledged messages. If `true`, then
138
+ # messages are not expunged from the subscription's backlog, even if
139
+ # they are acknowledged, until they fall out of the {#retention} window.
140
+ # Default is `false`.
141
+ #
142
+ # Makes an API call to retrieve the retain_acked value when called on a
143
+ # reference object. See {#reference?}.
144
+ #
145
+ # @return [Boolean] Returns `true` if acknowledged messages are
146
+ # retained.
147
+ #
148
+ def retain_acked
149
+ ensure_grpc!
150
+ @grpc.retain_acked_messages
151
+ end
152
+
153
+ ##
154
+ # Sets whether to retain acknowledged messages.
155
+ #
156
+ # @param [Boolean] new_retain_acked The new retain acknowledged messages
157
+ # value.
158
+ #
159
+ def retain_acked= new_retain_acked
160
+ update_grpc = Google::Cloud::PubSub::V1::Subscription.new name: name,
161
+ retain_acked_messages: !(!new_retain_acked)
162
+ @grpc = service.update_subscription update_grpc, :retain_acked_messages
163
+ @resource_name = nil
164
+ end
165
+
166
+ ##
167
+ # How long to retain unacknowledged messages in the subscription's
168
+ # backlog, from the moment a message is published. If
169
+ # {#retain_acked} is `true`, then this also configures the retention of
170
+ # acknowledged messages, and thus configures how far back in time a
171
+ # {#seek} can be done. Cannot be more than 604,800 seconds (7 days) or
172
+ # less than 600 seconds (10 minutes). Default is 604,800 seconds (7
173
+ # days).
174
+ #
175
+ # Makes an API call to retrieve the retention value when called on a
176
+ # reference object. See {#reference?}.
177
+ #
178
+ # @return [Numeric] The message retention duration in seconds.
179
+ #
180
+ def retention
181
+ ensure_grpc!
182
+ Convert.duration_to_number @grpc.message_retention_duration
183
+ end
184
+
185
+ ##
186
+ # Sets the message retention duration in seconds.
187
+ #
188
+ # @param [Numeric] new_retention The new retention value.
189
+ #
190
+ def retention= new_retention
191
+ new_retention_duration = Convert.number_to_duration new_retention
192
+ update_grpc = Google::Cloud::PubSub::V1::Subscription.new name: name,
193
+ message_retention_duration: new_retention_duration
194
+ @grpc = service.update_subscription update_grpc, :message_retention_duration
195
+ @resource_name = nil
196
+ end
197
+
102
198
  ##
103
199
  # Returns the URL locating the endpoint to which messages should be
104
- # pushed.
200
+ # pushed. For example, a Webhook endpoint might use
201
+ # `https://example.com/push`.
202
+ #
203
+ # Makes an API call to retrieve the endpoint value when called on a
204
+ # reference object. See {#reference?}.
205
+ #
206
+ # @return [String]
207
+ #
105
208
  def endpoint
106
209
  ensure_grpc!
107
- @grpc.push_config.push_endpoint if @grpc.push_config
210
+ @grpc.push_config&.push_endpoint
108
211
  end
109
212
 
110
213
  ##
111
214
  # Sets the URL locating the endpoint to which messages should be pushed.
215
+ # For example, a Webhook endpoint might use `https://example.com/push`.
216
+ #
217
+ # @param [String] new_endpoint The new endpoint value.
218
+ #
112
219
  def endpoint= new_endpoint
113
220
  ensure_service!
114
221
  service.modify_push_config name, new_endpoint, {}
115
- @grpc.push_config = Google::Pubsub::V1::PushConfig.new(
222
+
223
+ return if reference?
224
+
225
+ @grpc.push_config = Google::Cloud::PubSub::V1::PushConfig.new(
116
226
  push_endpoint: new_endpoint,
117
- attributes: {}
118
- ) if @grpc
227
+ attributes: {}
228
+ )
229
+ end
230
+
231
+ ##
232
+ # Inspect the Subscription's push configuration settings. The
233
+ # configuration can be changed by modifying the values in the method's
234
+ # block.
235
+ #
236
+ # Subscription objects that are reference only will return an empty
237
+ # {Subscription::PushConfig} object, which can be configured and saved
238
+ # using the method's block. Unlike {#endpoint}, which will retrieve the
239
+ # full resource from the API before returning. To get the actual values
240
+ # for a reference object, call {#reload!} before calling {#push_config}.
241
+ #
242
+ # @yield [push_config] a block for modifying the push configuration
243
+ # @yieldparam [Subscription::PushConfig] push_config the push
244
+ # configuration
245
+ #
246
+ # @return [Subscription::PushConfig]
247
+ #
248
+ # @example
249
+ # require "google/cloud/pubsub"
250
+ #
251
+ # pubsub = Google::Cloud::PubSub.new
252
+ #
253
+ # sub = pubsub.subscription "my-topic-sub"
254
+ # sub.push_config.endpoint #=> "http://example.com/callback"
255
+ # sub.push_config.authentication.email #=> "user@example.com"
256
+ # sub.push_config.authentication.audience #=> "client-12345"
257
+ #
258
+ # @example Update the push configuration by passing a block:
259
+ # require "google/cloud/pubsub"
260
+ #
261
+ # pubsub = Google::Cloud::PubSub.new
262
+ # sub = pubsub.subscription "my-subscription"
263
+ #
264
+ # sub.push_config do |pc|
265
+ # pc.endpoint = "http://example.net/callback"
266
+ # pc.set_oidc_token "user@example.net", "client-67890"
267
+ # end
268
+ #
269
+ def push_config
270
+ ensure_service!
271
+
272
+ orig_config = reference? ? nil : @grpc.push_config
273
+ config = PushConfig.from_grpc orig_config
274
+
275
+ if block_given?
276
+ old_config = config.to_grpc.dup
277
+ yield config
278
+ new_config = config.to_grpc
279
+
280
+ if old_config != new_config # has the object been changed?
281
+ update_grpc = Google::Cloud::PubSub::V1::Subscription.new name: name, push_config: new_config
282
+ @grpc = service.update_subscription update_grpc, :push_config
283
+ end
284
+ end
285
+
286
+ config.freeze
287
+ end
288
+
289
+ ##
290
+ # A hash of user-provided labels associated with this subscription.
291
+ # Labels can be used to organize and group subscriptions.See [Creating
292
+ # and Managing Labels](https://cloud.google.com/pubsub/docs/labels).
293
+ #
294
+ # The returned hash is frozen and changes are not allowed. Use
295
+ # {#labels=} to update the labels for this subscription.
296
+ #
297
+ # Makes an API call to retrieve the labels value when called on a
298
+ # reference object. See {#reference?}.
299
+ #
300
+ # @return [Hash] The frozen labels hash.
301
+ #
302
+ def labels
303
+ ensure_grpc!
304
+ @grpc.labels.to_h.freeze
305
+ end
306
+
307
+ ##
308
+ # Sets the hash of user-provided labels associated with this
309
+ # subscription. Labels can be used to organize and group subscriptions.
310
+ # Label keys and values can be no longer than 63 characters, can only
311
+ # contain lowercase letters, numeric characters, underscores and dashes.
312
+ # International characters are allowed. Label values are optional. Label
313
+ # keys must start with a letter and each label in the list must have a
314
+ # different key. See [Creating and Managing
315
+ # Labels](https://cloud.google.com/pubsub/docs/labels).
316
+ #
317
+ # @param [Hash] new_labels The new labels hash.
318
+ #
319
+ def labels= new_labels
320
+ raise ArgumentError, "Value must be a Hash" if new_labels.nil?
321
+ update_grpc = Google::Cloud::PubSub::V1::Subscription.new name: name, labels: new_labels
322
+ @grpc = service.update_subscription update_grpc, :labels
323
+ @resource_name = nil
324
+ end
325
+
326
+ ##
327
+ # The duration (in seconds) for when a subscription expires after the
328
+ # subscription goes inactive. A subscription is considered active as
329
+ # long as any connected subscriber is successfully consuming messages
330
+ # from the subscription or is issuing operations on the subscription.
331
+ #
332
+ # If {#expires_in=} is not set, a *default* value of of 31 days will be
333
+ # used. The minimum allowed value is 1 day.
334
+ #
335
+ # Makes an API call to retrieve the expires_in value when called on a
336
+ # reference object. See {#reference?}.
337
+ #
338
+ # @return [Numeric, nil] The expiration duration, or `nil` if unset.
339
+ #
340
+ def expires_in
341
+ ensure_grpc!
342
+
343
+ return nil if @grpc.expiration_policy.nil?
344
+
345
+ Convert.duration_to_number @grpc.expiration_policy.ttl
346
+ end
347
+
348
+ ##
349
+ # Sets the duration (in seconds) for when a subscription expires after
350
+ # the subscription goes inactive.
351
+ #
352
+ # See also {#expires_in}.
353
+ #
354
+ # @param [Numeric, nil] ttl The expiration duration in seconds, or `nil`
355
+ # to unset.
356
+ #
357
+ def expires_in= ttl
358
+ new_expiration_policy = Google::Cloud::PubSub::V1::ExpirationPolicy.new ttl: Convert.number_to_duration(ttl)
359
+
360
+ update_grpc = Google::Cloud::PubSub::V1::Subscription.new name: name, expiration_policy: new_expiration_policy
361
+ @grpc = service.update_subscription update_grpc, :expiration_policy
362
+ @resource_name = nil
363
+ end
364
+
365
+ ##
366
+ # An expression written in the Cloud Pub/Sub filter language. If non-empty, then only {Message} instances whose
367
+ # `attributes` field matches the filter are delivered on this subscription. If empty, then no messages are
368
+ # filtered out.
369
+ #
370
+ # Makes an API call to retrieve the filter value when called on a reference
371
+ # object. See {#reference?}.
372
+ #
373
+ # @return [String] The frozen filter string.
374
+ #
375
+ def filter
376
+ ensure_grpc!
377
+ @grpc.filter.freeze
378
+ end
379
+
380
+ ##
381
+ # Returns the {Topic} to which dead letter messages should be published if a dead letter policy is configured,
382
+ # otherwise `nil`. Dead lettering is done on a best effort basis. The same message might be dead lettered
383
+ # multiple times.
384
+ #
385
+ # See also {#dead_letter_topic=}, {#dead_letter_max_delivery_attempts=}, {#dead_letter_max_delivery_attempts}
386
+ # and {#remove_dead_letter_policy}.
387
+ #
388
+ # Makes an API call to retrieve the topic name when called on a reference object. See {#reference?}.
389
+ #
390
+ # @return [Topic, nil]
391
+ #
392
+ # @example
393
+ # require "google/cloud/pubsub"
394
+ #
395
+ # pubsub = Google::Cloud::PubSub.new
396
+ #
397
+ # sub = pubsub.subscription "my-topic-sub"
398
+ # sub.dead_letter_topic.name #=> "projects/my-project/topics/my-dead-letter-topic"
399
+ # sub.dead_letter_max_delivery_attempts #=> 10
400
+ #
401
+ def dead_letter_topic
402
+ ensure_grpc!
403
+ return nil unless @grpc.dead_letter_policy
404
+ Topic.from_name @grpc.dead_letter_policy.dead_letter_topic, service
405
+ end
406
+
407
+ ##
408
+ # Sets the {Topic} to which dead letter messages for the subscription should be published. Dead lettering is
409
+ # done on a best effort basis. The same message might be dead lettered multiple times.
410
+ # The Cloud Pub/Sub service account associated with the enclosing subscription's parent project (i.e.,
411
+ # `service-\\{project_number}@gcp-sa-pubsub.iam.gserviceaccount.com`) must have permission to Publish() to this
412
+ # topic.
413
+ #
414
+ # The operation will fail if the topic does not exist. Users should ensure that there is a subscription attached
415
+ # to this topic since messages published to a topic with no subscriptions are lost.
416
+ #
417
+ # Makes an API call to retrieve the dead_letter_policy value when called on a
418
+ # reference object. See {#reference?}.
419
+ #
420
+ # See also {#dead_letter_topic}, {#dead_letter_max_delivery_attempts=}, {#dead_letter_max_delivery_attempts}
421
+ # and {#remove_dead_letter_policy}.
422
+ #
423
+ # @param [Topic] new_dead_letter_topic The topic to which dead letter messages for the subscription should be
424
+ # published.
425
+ #
426
+ # @example
427
+ # require "google/cloud/pubsub"
428
+ #
429
+ # pubsub = Google::Cloud::PubSub.new
430
+ #
431
+ # sub = pubsub.subscription "my-topic-sub"
432
+ # dead_letter_topic = pubsub.topic "my-dead-letter-topic", skip_lookup: true
433
+ # sub.dead_letter_topic = dead_letter_topic
434
+ #
435
+ def dead_letter_topic= new_dead_letter_topic
436
+ ensure_grpc!
437
+ dead_letter_policy = @grpc.dead_letter_policy || Google::Cloud::PubSub::V1::DeadLetterPolicy.new
438
+ dead_letter_policy.dead_letter_topic = new_dead_letter_topic.name
439
+ update_grpc = Google::Cloud::PubSub::V1::Subscription.new name: name, dead_letter_policy: dead_letter_policy
440
+ @grpc = service.update_subscription update_grpc, :dead_letter_policy
441
+ @resource_name = nil
442
+ end
443
+
444
+ ##
445
+ # Returns the maximum number of delivery attempts for any message in the subscription's dead letter policy if a
446
+ # dead letter policy is configured, otherwise `nil`. Dead lettering is done on a best effort basis. The same
447
+ # message might be dead lettered multiple times. The value must be between 5 and 100.
448
+ #
449
+ # The number of delivery attempts is defined as 1 + (the sum of number of NACKs and number of times the
450
+ # acknowledgement deadline has been exceeded for the message). A NACK is any call to ModifyAckDeadline with a 0
451
+ # deadline. Note that client libraries may automatically extend ack_deadlines.
452
+ #
453
+ # This field will be honored on a best effort basis. If this parameter is `nil` or `0`, a default value of `5`
454
+ # is used.
455
+ #
456
+ # See also {#dead_letter_max_delivery_attempts=}, {#dead_letter_topic=}, {#dead_letter_topic}
457
+ # and {#remove_dead_letter_policy}.
458
+ #
459
+ # Makes an API call to retrieve the dead_letter_policy when called on a reference object. See {#reference?}.
460
+ #
461
+ # @return [Integer, nil] A value between `5` and `100`, or `nil` if no dead letter policy is configured.
462
+ #
463
+ # @example
464
+ # require "google/cloud/pubsub"
465
+ #
466
+ # pubsub = Google::Cloud::PubSub.new
467
+ #
468
+ # sub = pubsub.subscription "my-topic-sub"
469
+ # sub.dead_letter_topic.name #=> "projects/my-project/topics/my-dead-letter-topic"
470
+ # sub.dead_letter_max_delivery_attempts #=> 10
471
+ #
472
+ def dead_letter_max_delivery_attempts
473
+ ensure_grpc!
474
+ @grpc.dead_letter_policy&.max_delivery_attempts
475
+ end
476
+
477
+ ##
478
+ # Sets the maximum number of delivery attempts for any message in the subscription's dead letter policy.
479
+ # Dead lettering is done on a best effort basis. The same message might be dead lettered multiple times.
480
+ # The value must be between 5 and 100.
481
+ #
482
+ # The number of delivery attempts is defined as 1 + (the sum of number of NACKs and number of times the
483
+ # acknowledgement deadline has been exceeded for the message). A NACK is any call to ModifyAckDeadline with a 0
484
+ # deadline. Note that client libraries may automatically extend ack_deadlines.
485
+ #
486
+ # This field will be honored on a best effort basis. If this parameter is 0, a default value of 5 is used.
487
+ #
488
+ # Makes an API call to retrieve the dead_letter_policy when called on a reference object. See {#reference?}.
489
+ #
490
+ # The dead letter topic must be set first. See {#dead_letter_topic=}, {#dead_letter_topic} and
491
+ # {#remove_dead_letter_policy}.
492
+ #
493
+ # @param [Integer, nil] new_dead_letter_max_delivery_attempts A value between 5 and 100. If this parameter is
494
+ # `nil` or `0`, a default value of 5 is used.
495
+ #
496
+ # @raise [ArgumentError] if the dead letter topic has not been set. See {#dead_letter_topic=}.
497
+ #
498
+ # @example
499
+ # require "google/cloud/pubsub"
500
+ #
501
+ # pubsub = Google::Cloud::PubSub.new
502
+ #
503
+ # sub = pubsub.subscription "my-topic-sub"
504
+ # sub.dead_letter_topic.name #=> "projects/my-project/topics/my-dead-letter-topic"
505
+ #
506
+ # sub.dead_letter_max_delivery_attempts = 20
507
+ #
508
+ def dead_letter_max_delivery_attempts= new_dead_letter_max_delivery_attempts
509
+ ensure_grpc!
510
+ unless @grpc.dead_letter_policy&.dead_letter_topic
511
+ # Service error message "3:Invalid resource name given (name=)." does not identify param.
512
+ raise ArgumentError, "dead_letter_topic is required with dead_letter_max_delivery_attempts"
513
+ end
514
+ dead_letter_policy = @grpc.dead_letter_policy || Google::Cloud::PubSub::V1::DeadLetterPolicy.new
515
+ dead_letter_policy.max_delivery_attempts = new_dead_letter_max_delivery_attempts
516
+ update_grpc = Google::Cloud::PubSub::V1::Subscription.new name: name, dead_letter_policy: dead_letter_policy
517
+ @grpc = service.update_subscription update_grpc, :dead_letter_policy
518
+ @resource_name = nil
519
+ end
520
+
521
+ ##
522
+ # Removes an existing dead letter policy. A dead letter policy specifies the conditions for dead lettering
523
+ # messages in the subscription. If a dead letter policy is not set, dead lettering is disabled.
524
+ #
525
+ # Makes an API call to retrieve the dead_letter_policy when called on a reference object. See {#reference?}.
526
+ #
527
+ # See {#dead_letter_topic}, {#dead_letter_topic=}, {#dead_letter_max_delivery_attempts} and
528
+ # {#dead_letter_max_delivery_attempts=}.
529
+ #
530
+ # @return [Boolean] `true` if an existing dead letter policy was removed, `false` if no existing dead letter
531
+ # policy was present.
532
+ #
533
+ # @example
534
+ # require "google/cloud/pubsub"
535
+ #
536
+ # pubsub = Google::Cloud::PubSub.new
537
+ #
538
+ # sub = pubsub.subscription "my-topic-sub"
539
+ #
540
+ # sub.dead_letter_topic.name #=> "projects/my-project/topics/my-dead-letter-topic"
541
+ # sub.dead_letter_max_delivery_attempts #=> 10
542
+ #
543
+ # sub.remove_dead_letter_policy
544
+ #
545
+ # sub.dead_letter_topic #=> nil
546
+ # sub.dead_letter_max_delivery_attempts #=> nil
547
+ #
548
+ def remove_dead_letter_policy
549
+ ensure_grpc!
550
+ return false if @grpc.dead_letter_policy.nil?
551
+ update_grpc = Google::Cloud::PubSub::V1::Subscription.new name: name, dead_letter_policy: nil
552
+ @grpc = service.update_subscription update_grpc, :dead_letter_policy
553
+ true
554
+ end
555
+
556
+ ##
557
+ # A policy that specifies how Cloud Pub/Sub retries message delivery for this subscription. If `nil`, the
558
+ # default retry policy is applied. This generally implies that messages will be retried as soon as possible
559
+ # for healthy subscribers. Retry Policy will be triggered on NACKs or acknowledgement deadline exceeded events
560
+ # for a given message.
561
+ #
562
+ # Makes an API call to retrieve the retry_policy when called on a reference object. See {#reference?}.
563
+ #
564
+ # @return [RetryPolicy, nil] The retry policy for the subscription, or `nil`.
565
+ #
566
+ # @example
567
+ # require "google/cloud/pubsub"
568
+ #
569
+ # pubsub = Google::Cloud::PubSub.new
570
+ #
571
+ # sub = pubsub.subscription "my-topic-sub"
572
+ #
573
+ # sub.retry_policy = Google::Cloud::PubSub::RetryPolicy.new minimum_backoff: 5, maximum_backoff: 300
574
+ #
575
+ # sub.retry_policy.minimum_backoff #=> 5
576
+ # sub.retry_policy.maximum_backoff #=> 300
577
+ #
578
+ def retry_policy
579
+ ensure_grpc!
580
+ return nil unless @grpc.retry_policy
581
+ RetryPolicy.from_grpc @grpc.retry_policy
582
+ end
583
+
584
+ ##
585
+ # Sets a policy that specifies how Cloud Pub/Sub retries message delivery for this subscription. If `nil`, the
586
+ # default retry policy is applied. This generally implies that messages will be retried as soon as possible
587
+ # for healthy subscribers. Retry Policy will be triggered on NACKs or acknowledgement deadline exceeded events
588
+ # for a given message.
589
+ #
590
+ # @param [RetryPolicy, nil] new_retry_policy A new retry policy for the subscription, or `nil`.
591
+ #
592
+ # @example
593
+ # require "google/cloud/pubsub"
594
+ #
595
+ # pubsub = Google::Cloud::PubSub.new
596
+ #
597
+ # sub = pubsub.subscription "my-topic-sub"
598
+ #
599
+ # sub.retry_policy = Google::Cloud::PubSub::RetryPolicy.new minimum_backoff: 5, maximum_backoff: 300
600
+ #
601
+ # sub.retry_policy.minimum_backoff #=> 5
602
+ # sub.retry_policy.maximum_backoff #=> 300
603
+ #
604
+ def retry_policy= new_retry_policy
605
+ ensure_service!
606
+ new_retry_policy = new_retry_policy.to_grpc if new_retry_policy
607
+ update_grpc = Google::Cloud::PubSub::V1::Subscription.new name: name, retry_policy: new_retry_policy
608
+ @grpc = service.update_subscription update_grpc, :retry_policy
609
+ @resource_name = nil
610
+ end
611
+
612
+ ##
613
+ # Whether message ordering has been enabled. When enabled, messages
614
+ # published with the same `ordering_key` will be delivered in the order
615
+ # they were published. When disabled, messages may be delivered in any
616
+ # order.
617
+ #
618
+ # @note At the time of this release, ordering keys are not yet publicly
619
+ # enabled and requires special project enablements.
620
+ #
621
+ # See {Topic#publish_async}, {#listen}, and {Message#ordering_key}.
622
+ #
623
+ # Makes an API call to retrieve the enable_message_ordering value when called on a
624
+ # reference object. See {#reference?}.
625
+ #
626
+ # @return [Boolean]
627
+ #
628
+ def message_ordering?
629
+ ensure_grpc!
630
+ @grpc.enable_message_ordering
631
+ end
632
+
633
+ ##
634
+ # Whether the subscription is detached from its topic. Detached subscriptions don't receive messages from their
635
+ # topic and don't retain any backlog. {#pull} and {#listen} (pull and streaming pull) operations will raise
636
+ # `FAILED_PRECONDITION`. If the subscription is a push subscription (see {#push_config}), pushes to the endpoint
637
+ # will not be made. The default value is `false`.
638
+ #
639
+ # See {Topic#subscribe} and {#detach}.
640
+ #
641
+ # Makes an API call to retrieve the detached value when called on a
642
+ # reference object. See {#reference?}.
643
+ #
644
+ # @return [Boolean]
645
+ #
646
+ # @example
647
+ # require "google/cloud/pubsub"
648
+ #
649
+ # pubsub = Google::Cloud::PubSub.new
650
+ #
651
+ # sub = pubsub.subscription "my-topic-sub"
652
+ # sub.detach
653
+ #
654
+ # # sleep 120
655
+ # sub.detached? #=> true
656
+ #
657
+ def detached?
658
+ ensure_grpc!
659
+ @grpc.detached
119
660
  end
120
661
 
121
662
  ##
122
663
  # Determines whether the subscription exists in the Pub/Sub service.
123
664
  #
665
+ # Makes an API call to determine whether the subscription resource
666
+ # exists when called on a reference object. See {#reference?}.
667
+ #
668
+ # @return [Boolean]
669
+ #
124
670
  # @example
125
- # require "google/cloud"
671
+ # require "google/cloud/pubsub"
126
672
  #
127
- # gcloud = Google::Cloud.new
128
- # pubsub = gcloud.pubsub
673
+ # pubsub = Google::Cloud::PubSub.new
129
674
  #
130
675
  # sub = pubsub.subscription "my-topic-sub"
131
676
  # sub.exists? #=> true
132
677
  #
133
678
  def exists?
134
- # Always true if we have a grpc object
135
- return true unless @grpc.nil?
679
+ # Always true if the object is not set as reference
680
+ return true unless reference?
136
681
  # If we have a value, return it
137
682
  return @exists unless @exists.nil?
138
683
  ensure_grpc!
139
- @exists = !@grpc.nil?
684
+ @exists = true
140
685
  rescue Google::Cloud::NotFoundError
141
686
  @exists = false
142
687
  end
143
688
 
144
689
  ##
145
- # @private
146
- # Determines whether the subscription object was created with an
147
- # HTTP call.
690
+ # Deletes an existing subscription.
691
+ # All pending messages in the subscription are immediately dropped.
692
+ #
693
+ # @return [Boolean] Returns `true` if the subscription was deleted.
148
694
  #
149
695
  # @example
150
- # require "google/cloud"
696
+ # require "google/cloud/pubsub"
151
697
  #
152
- # gcloud = Google::Cloud.new
153
- # pubsub = gcloud.pubsub
698
+ # pubsub = Google::Cloud::PubSub.new
154
699
  #
155
- # sub = pubsub.get_subscription "my-topic-sub"
156
- # sub.lazy? #=> false
700
+ # sub = pubsub.subscription "my-topic-sub"
701
+ # sub.delete
157
702
  #
158
- def lazy?
159
- @grpc.nil?
703
+ def delete
704
+ ensure_service!
705
+ service.delete_subscription name
706
+ true
160
707
  end
161
708
 
162
709
  ##
163
- # Deletes an existing subscription.
164
- # All pending messages in the subscription are immediately dropped.
710
+ # Detaches a subscription from its topic. All messages retained in the subscription are dropped. Detached
711
+ # subscriptions don't receive messages from their topic and don't retain any backlog. Subsequent {#pull} and
712
+ # {#listen} (pull and streaming pull) operations will raise `FAILED_PRECONDITION`. If the subscription is a push
713
+ # subscription (see {#push_config}), pushes to the endpoint will stop. It may take a few minutes for the
714
+ # subscription's detached state to be reflected in subsequent calls to {#detached?}.
165
715
  #
166
- # @return [Boolean] Returns `true` if the subscription was deleted.
716
+ # @return [Boolean] Returns `true` if the detach operation was successful.
167
717
  #
168
718
  # @example
169
- # require "google/cloud"
719
+ # require "google/cloud/pubsub"
170
720
  #
171
- # gcloud = Google::Cloud.new
172
- # pubsub = gcloud.pubsub
721
+ # pubsub = Google::Cloud::PubSub.new
173
722
  #
174
723
  # sub = pubsub.subscription "my-topic-sub"
175
- # sub.delete
724
+ # sub.detach
176
725
  #
177
- def delete
726
+ # # sleep 120
727
+ # sub.detached? #=> true
728
+ #
729
+ def detach
178
730
  ensure_service!
179
- service.delete_subscription name
731
+ service.detach_subscription name
180
732
  true
181
733
  end
182
734
 
183
735
  ##
184
- # Pulls messages from the server. Returns an empty list if there are no
185
- # messages available in the backlog. Raises an ApiError with status
186
- # `UNAVAILABLE` if there are too many concurrent pull requests pending
187
- # for the given subscription.
736
+ # Pulls messages from the server, blocking until messages are available
737
+ # when called with the `immediate: false` option, which is recommended
738
+ # to avoid adverse impacts on the performance of pull operations.
739
+ #
740
+ # Raises an API error with status `UNAVAILABLE` if there are too many
741
+ # concurrent pull requests pending for the given subscription.
742
+ #
743
+ # See also {#listen} for the preferred way to process messages as they
744
+ # become available.
188
745
  #
189
- # @param [Boolean] immediate When `true` the system will respond
190
- # immediately even if it is not able to return messages. When `false`
191
- # the system is allowed to wait until it can return least one message.
192
- # No messages are returned when a request times out. The default value
193
- # is `true`.
746
+ # @param [Boolean] immediate Whether to return immediately or block until
747
+ # messages are available.
748
+ #
749
+ # **Warning:** The default value of this field is `true`. However, sending
750
+ # `true` is discouraged because it adversely impacts the performance of
751
+ # pull operations. We recommend that users always explicitly set this field
752
+ # to `false`.
753
+ #
754
+ # If this field set to `true`, the system will respond immediately
755
+ # even if it there are no messages available to return in the pull
756
+ # response. Otherwise, the system may wait (for a bounded amount of time)
757
+ # until at least one message is available, rather than returning no messages.
758
+ #
759
+ # See also {#listen} for the preferred way to process messages as they
760
+ # become available.
194
761
  # @param [Integer] max The maximum number of messages to return for this
195
762
  # request. The Pub/Sub system may return fewer than the number
196
763
  # specified. The default value is `100`, the maximum value is `1000`.
197
- # @param [Boolean] autoack Automatically acknowledge the message as it
198
- # is pulled. The default value is `false`.
199
764
  #
200
- # @return [Array<Google::Cloud::Pubsub::ReceivedMessage>]
765
+ # @return [Array<Google::Cloud::PubSub::ReceivedMessage>]
201
766
  #
202
- # @example
203
- # require "google/cloud"
767
+ # @example The `immediate: false` option is now recommended to avoid adverse impacts on pull operations:
768
+ # require "google/cloud/pubsub"
204
769
  #
205
- # gcloud = Google::Cloud.new
206
- # pubsub = gcloud.pubsub
770
+ # pubsub = Google::Cloud::PubSub.new
207
771
  #
208
772
  # sub = pubsub.subscription "my-topic-sub"
209
- # sub.pull.each { |msg| msg.acknowledge! }
773
+ # received_messages = sub.pull immediate: false
774
+ # received_messages.each do |received_message|
775
+ # received_message.acknowledge!
776
+ # end
210
777
  #
211
778
  # @example A maximum number of messages returned can also be specified:
212
- # require "google/cloud"
213
- #
214
- # gcloud = Google::Cloud.new
215
- # pubsub = gcloud.pubsub
779
+ # require "google/cloud/pubsub"
216
780
  #
217
- # sub = pubsub.subscription "my-topic-sub", max: 10
218
- # sub.pull.each { |msg| msg.acknowledge! }
219
- #
220
- # @example The call can block until messages are available:
221
- # require "google/cloud"
222
- #
223
- # gcloud = Google::Cloud.new
224
- # pubsub = gcloud.pubsub
781
+ # pubsub = Google::Cloud::PubSub.new
225
782
  #
226
783
  # sub = pubsub.subscription "my-topic-sub"
227
- # msgs = sub.pull immediate: false
228
- # msgs.each { |msg| msg.acknowledge! }
784
+ # received_messages = sub.pull immediate: false, max: 10
785
+ # received_messages.each do |received_message|
786
+ # received_message.acknowledge!
787
+ # end
229
788
  #
230
- def pull immediate: true, max: 100, autoack: false
789
+ def pull immediate: true, max: 100
231
790
  ensure_service!
232
791
  options = { immediate: immediate, max: max }
233
792
  list_grpc = service.pull name, options
234
- messages = Array(list_grpc.received_messages).map do |msg_grpc|
793
+ Array(list_grpc.received_messages).map do |msg_grpc|
235
794
  ReceivedMessage.from_grpc msg_grpc, self
236
795
  end
237
- acknowledge messages if autoack
238
- messages
239
796
  rescue Google::Cloud::DeadlineExceededError
240
797
  []
241
798
  end
@@ -246,86 +803,194 @@ module Google
246
803
  #
247
804
  # subscription.pull immediate: false
248
805
  #
806
+ # See also {#listen} for the preferred way to process messages as they
807
+ # become available.
808
+ #
249
809
  # @param [Integer] max The maximum number of messages to return for this
250
810
  # request. The Pub/Sub system may return fewer than the number
251
811
  # specified. The default value is `100`, the maximum value is `1000`.
252
- # @param [Boolean] autoack Automatically acknowledge the message as it
253
- # is pulled. The default value is `false`.
254
812
  #
255
- # @return [Array<Google::Cloud::Pubsub::ReceivedMessage>]
813
+ # @return [Array<Google::Cloud::PubSub::ReceivedMessage>]
256
814
  #
257
815
  # @example
258
- # require "google/cloud"
816
+ # require "google/cloud/pubsub"
259
817
  #
260
- # gcloud = Google::Cloud.new
261
- # pubsub = gcloud.pubsub
818
+ # pubsub = Google::Cloud::PubSub.new
262
819
  #
263
820
  # sub = pubsub.subscription "my-topic-sub"
264
- # msgs = sub.wait_for_messages
265
- # msgs.each { |msg| msg.acknowledge! }
821
+ # received_messages = sub.wait_for_messages
822
+ # received_messages.each do |received_message|
823
+ # received_message.acknowledge!
824
+ # end
266
825
  #
267
- def wait_for_messages max: 100, autoack: false
268
- pull immediate: false, max: max, autoack: autoack
826
+ def wait_for_messages max: 100
827
+ pull immediate: false, max: max
269
828
  end
270
829
 
271
830
  ##
272
- # Poll the backend for new messages. This runs a loop to ping the API,
273
- # blocking indefinitely, yielding retrieved messages as they are
274
- # received.
275
- #
276
- # @param [Integer] max The maximum number of messages to return for this
277
- # request. The Pub/Sub system may return fewer than the number
278
- # specified. The default value is `100`, the maximum value is `1000`.
279
- # @param [Boolean] autoack Automatically acknowledge the message as it
280
- # is pulled. The default value is `false`.
281
- # @param [Number] delay The number of seconds to pause between requests
282
- # when the Google Cloud service has no messages to return. The default
283
- # value is `1`.
284
- # @yield [msg] a block for processing new messages
285
- # @yieldparam [ReceivedMessage] msg the newly received message
831
+ # Create a {Subscriber} object that receives and processes messages
832
+ # using the code provided in the callback. Messages passed to the
833
+ # callback should acknowledge ({ReceivedMessage#acknowledge!}) or reject
834
+ # ({ReceivedMessage#reject!}) the message. If no action is taken, the
835
+ # message will be removed from the subscriber and made available for
836
+ # redelivery after the callback is completed.
837
+ #
838
+ # Google Cloud Pub/Sub ordering keys provide the ability to ensure
839
+ # related messages are sent to subscribers in the order in which they
840
+ # were published. Messages can be tagged with an ordering key, a string
841
+ # that identifies related messages for which publish order should be
842
+ # respected. The service guarantees that, for a given ordering key and
843
+ # publisher, messages are sent to subscribers in the order in which they
844
+ # were published. Ordering does not require sacrificing high throughput
845
+ # or scalability, as the service automatically distributes messages for
846
+ # different ordering keys across subscribers.
847
+ #
848
+ # To use ordering keys, the subscription must be created with message
849
+ # ordering enabled (See {Topic#subscribe} and {#message_ordering?})
850
+ # before calling {#listen}. When enabled, the subscriber will deliver
851
+ # messages with the same `ordering_key` in the order they were
852
+ # published.
853
+ #
854
+ # @note At the time of this release, ordering keys are not yet publicly
855
+ # enabled and requires special project enablements.
856
+ #
857
+ # @param [Numeric] deadline The default number of seconds the stream
858
+ # will hold received messages before modifying the message's ack
859
+ # deadline. The minimum is 10, the maximum is 600. Default is
860
+ # {#deadline}. Optional.
861
+ #
862
+ # When using a reference object an API call will be made to retrieve
863
+ # the default deadline value for the subscription when this argument
864
+ # is not provided. See {#reference?}.
865
+ # @param [Boolean] message_ordering Whether message ordering has been
866
+ # enabled. The value provided must match the value set on the Pub/Sub
867
+ # service. See {#message_ordering?}. Optional.
868
+ #
869
+ # When using a reference object an API call will be made to retrieve
870
+ # the default message_ordering value for the subscription when this
871
+ # argument is not provided. See {#reference?}.
872
+ # @param [Integer] streams The number of concurrent streams to open to
873
+ # pull messages from the subscription. Default is 4. Optional.
874
+ # @param [Hash, Integer] inventory The settings to control how received messages are to be handled by the
875
+ # subscriber. When provided as an Integer instead of a Hash only `max_outstanding_messages` will be set.
876
+ # Optional.
877
+ #
878
+ # Hash keys and values may include the following:
879
+ #
880
+ # * `:max_outstanding_messages` [Integer] The number of received messages to be collected by subscriber.
881
+ # Default is 1,000. (Note: replaces `:limit`, which is deprecated.)
882
+ # * `:max_outstanding_bytes` [Integer] The total byte size of received messages to be collected by
883
+ # subscriber. Default is 100,000,000 (100MB). (Note: replaces `:bytesize`, which is deprecated.)
884
+ # * `:use_legacy_flow_control` [Boolean] Disables enforcing flow control settings at the Cloud PubSub
885
+ # server and the less accurate method of only enforcing flow control at the client side is used instead.
886
+ # Default is false.
887
+ # * `:max_total_lease_duration` [Integer] The number of seconds that received messages can be held awaiting
888
+ # processing. Default is 3,600 (1 hour). (Note: replaces `:extension`, which is deprecated.)
889
+ # * `:max_duration_per_lease_extension` [Integer] The maximum amount of time in seconds for a single lease
890
+ # extension attempt. Bounds the delay before a message redelivery if the subscriber fails to extend the
891
+ # deadline. Default is 0 (disabled).
892
+ # @param [Hash] threads The number of threads to create to handle
893
+ # concurrent calls by each stream opened by the subscriber. Optional.
894
+ #
895
+ # Hash keys and values may include the following:
896
+ #
897
+ # * `:callback` (Integer) The number of threads used to handle the
898
+ # received messages. Default is 8.
899
+ # * `:push` (Integer) The number of threads to handle
900
+ # acknowledgement ({ReceivedMessage#ack!}) and modify ack deadline
901
+ # messages ({ReceivedMessage#nack!},
902
+ # {ReceivedMessage#modify_ack_deadline!}). Default is 4.
903
+ #
904
+ # @yield [received_message] a block for processing new messages
905
+ # @yieldparam [ReceivedMessage] received_message the newly received
906
+ # message
907
+ #
908
+ # @return [Subscriber]
286
909
  #
287
910
  # @example
288
- # require "google/cloud"
911
+ # require "google/cloud/pubsub"
289
912
  #
290
- # gcloud = Google::Cloud.new
291
- # pubsub = gcloud.pubsub
913
+ # pubsub = Google::Cloud::PubSub.new
292
914
  #
293
915
  # sub = pubsub.subscription "my-topic-sub"
294
- # sub.listen do |msg|
295
- # # process msg
916
+ #
917
+ # subscriber = sub.listen do |received_message|
918
+ # # process message
919
+ # puts "Data: #{received_message.message.data}, published at #{received_message.message.published_at}"
920
+ # received_message.acknowledge!
296
921
  # end
297
922
  #
298
- # @example Limit number of messages pulled per API request with `max`:
299
- # require "google/cloud"
923
+ # # Start background threads that will call block passed to listen.
924
+ # subscriber.start
925
+ #
926
+ # # Shut down the subscriber when ready to stop receiving messages.
927
+ # subscriber.stop!
928
+ #
929
+ # @example Configuring to increase concurrent callbacks:
930
+ # require "google/cloud/pubsub"
300
931
  #
301
- # gcloud = Google::Cloud.new
302
- # pubsub = gcloud.pubsub
932
+ # pubsub = Google::Cloud::PubSub.new
303
933
  #
304
934
  # sub = pubsub.subscription "my-topic-sub"
305
- # sub.listen max: 20 do |msg|
306
- # # process msg
935
+ #
936
+ # subscriber = sub.listen threads: { callback: 16 } do |rec_message|
937
+ # # store the message somewhere before acknowledging
938
+ # store_in_backend rec_message.data # takes a few seconds
939
+ # rec_message.acknowledge!
940
+ # end
941
+ #
942
+ # # Start background threads that will call block passed to listen.
943
+ # subscriber.start
944
+ #
945
+ # # Shut down the subscriber when ready to stop receiving messages.
946
+ # subscriber.stop!
947
+ #
948
+ # @example Ordered messages are supported using ordering_key:
949
+ # require "google/cloud/pubsub"
950
+ #
951
+ # pubsub = Google::Cloud::PubSub.new
952
+ #
953
+ # sub = pubsub.subscription "my-ordered-topic-sub"
954
+ # sub.message_ordering? #=> true
955
+ #
956
+ # subscriber = sub.listen do |received_message|
957
+ # # messsages with the same ordering_key are received
958
+ # # in the order in which they were published.
959
+ # received_message.acknowledge!
307
960
  # end
308
961
  #
309
- # @example Automatically acknowledge messages with `autoack`:
310
- # require "google/cloud"
962
+ # # Start background threads that will call block passed to listen.
963
+ # subscriber.start
311
964
  #
312
- # gcloud = Google::Cloud.new
313
- # pubsub = gcloud.pubsub
965
+ # # Shut down the subscriber when ready to stop receiving messages.
966
+ # subscriber.stop!
967
+ #
968
+ # @example Set the maximum amount of time before redelivery if the subscriber fails to extend the deadline:
969
+ # require "google/cloud/pubsub"
970
+ #
971
+ # pubsub = Google::Cloud::PubSub.new
314
972
  #
315
973
  # sub = pubsub.subscription "my-topic-sub"
316
- # sub.listen autoack: true do |msg|
317
- # # process msg
974
+ #
975
+ # subscriber = sub.listen inventory: { max_duration_per_lease_extension: 20 } do |received_message|
976
+ # # Process message very slowly with possibility of failure.
977
+ # process rec_message.data # takes minutes
978
+ # rec_message.acknowledge!
318
979
  # end
319
980
  #
320
- def listen max: 100, autoack: false, delay: 1
321
- loop do
322
- msgs = wait_for_messages max: max, autoack: autoack
323
- if msgs.any?
324
- msgs.each { |msg| yield msg }
325
- else
326
- sleep delay
327
- end
328
- end
981
+ # # Start background threads that will call block passed to listen.
982
+ # subscriber.start
983
+ #
984
+ # # Shut down the subscriber when ready to stop receiving messages.
985
+ # subscriber.stop!
986
+ #
987
+ def listen deadline: nil, message_ordering: nil, streams: nil, inventory: nil, threads: {}, &block
988
+ ensure_service!
989
+ deadline ||= self.deadline
990
+ message_ordering = message_ordering? if message_ordering.nil?
991
+
992
+ Subscriber.new name, block, deadline: deadline, streams: streams, inventory: inventory,
993
+ message_ordering: message_ordering, threads: threads, service: service
329
994
  end
330
995
 
331
996
  ##
@@ -336,18 +1001,19 @@ module Google
336
1001
  # Acknowledging a message more than once will not result in an error.
337
1002
  # This is only used for messages received via pull.
338
1003
  #
1004
+ # See also {ReceivedMessage#acknowledge!}.
1005
+ #
339
1006
  # @param [ReceivedMessage, String] messages One or more
340
1007
  # {ReceivedMessage} objects or ack_id values.
341
1008
  #
342
1009
  # @example
343
- # require "google/cloud"
1010
+ # require "google/cloud/pubsub"
344
1011
  #
345
- # gcloud = Google::Cloud.new
346
- # pubsub = gcloud.pubsub
1012
+ # pubsub = Google::Cloud::PubSub.new
347
1013
  #
348
1014
  # sub = pubsub.subscription "my-topic-sub"
349
- # messages = sub.pull
350
- # sub.acknowledge messages
1015
+ # received_messages = sub.pull immediate: false
1016
+ # sub.acknowledge received_messages
351
1017
  #
352
1018
  def acknowledge *messages
353
1019
  ack_ids = coerce_ack_ids messages
@@ -356,7 +1022,7 @@ module Google
356
1022
  service.acknowledge name, *ack_ids
357
1023
  true
358
1024
  end
359
- alias_method :ack, :acknowledge
1025
+ alias ack acknowledge
360
1026
 
361
1027
  ##
362
1028
  # Modifies the acknowledge deadline for messages.
@@ -365,6 +1031,8 @@ module Google
365
1031
  # make the messages available for redelivery if the processing was
366
1032
  # interrupted.
367
1033
  #
1034
+ # See also {ReceivedMessage#modify_ack_deadline!}.
1035
+ #
368
1036
  # @param [Integer] new_deadline The new ack deadline in seconds from the
369
1037
  # time this request is sent to the Pub/Sub system. Must be >= 0. For
370
1038
  # example, if the value is `10`, the new ack deadline will expire 10
@@ -374,34 +1042,200 @@ module Google
374
1042
  # {ReceivedMessage} objects or ack_id values.
375
1043
  #
376
1044
  # @example
377
- # require "google/cloud"
1045
+ # require "google/cloud/pubsub"
378
1046
  #
379
- # gcloud = Google::Cloud.new
380
- # pubsub = gcloud.pubsub
1047
+ # pubsub = Google::Cloud::PubSub.new
381
1048
  #
382
1049
  # sub = pubsub.subscription "my-topic-sub"
383
- # messages = sub.pull
384
- # sub.delay 120, messages
1050
+ # received_messages = sub.pull immediate: false
1051
+ # sub.modify_ack_deadline 120, received_messages
385
1052
  #
386
- def delay new_deadline, *messages
1053
+ def modify_ack_deadline new_deadline, *messages
387
1054
  ack_ids = coerce_ack_ids messages
388
1055
  ensure_service!
389
1056
  service.modify_ack_deadline name, ack_ids, new_deadline
390
1057
  true
391
1058
  end
392
1059
 
1060
+ ##
1061
+ # Creates a new {Snapshot} from the subscription. The created snapshot
1062
+ # is guaranteed to retain:
1063
+ #
1064
+ # * The existing backlog on the subscription. More precisely, this is
1065
+ # defined as the messages in the subscription's backlog that are
1066
+ # unacknowledged upon the successful completion of the
1067
+ # `create_snapshot` operation; as well as:
1068
+ # * Any messages published to the subscription's topic following the
1069
+ # successful completion of the `create_snapshot` operation.
1070
+ #
1071
+ # @param [String, nil] snapshot_name Name of the new snapshot. Optional.
1072
+ # If the name is not provided, the server will assign a random name
1073
+ # for this snapshot on the same project as the subscription.
1074
+ # The value can be a simple snapshot ID (relative name), in which
1075
+ # case the current project ID will be supplied, or a fully-qualified
1076
+ # snapshot name in the form
1077
+ # `projects/{project_id}/snapshots/{snapshot_id}`.
1078
+ #
1079
+ # The snapshot ID (relative name) must start with a letter, and
1080
+ # contain only letters (`[A-Za-z]`), numbers (`[0-9]`), dashes (`-`),
1081
+ # underscores (`_`), periods (`.`), tildes (`~`), plus (`+`) or percent
1082
+ # signs (`%`). It must be between 3 and 255 characters in length, and
1083
+ # it must not start with `goog`.
1084
+ # @param [Hash] labels A hash of user-provided labels associated with
1085
+ # the snapshot. You can use these to organize and group your
1086
+ # snapshots. Label keys and values can be no longer than 63
1087
+ # characters, can only contain lowercase letters, numeric characters,
1088
+ # underscores and dashes. International characters are allowed. Label
1089
+ # values are optional. Label keys must start with a letter and each
1090
+ # label in the list must have a different key. See [Creating and
1091
+ # Managing Labels](https://cloud.google.com/pubsub/docs/labels).
1092
+ #
1093
+ # @return [Google::Cloud::PubSub::Snapshot]
1094
+ #
1095
+ # @example
1096
+ # require "google/cloud/pubsub"
1097
+ #
1098
+ # pubsub = Google::Cloud::PubSub.new
1099
+ # sub = pubsub.subscription "my-sub"
1100
+ #
1101
+ # snapshot = sub.create_snapshot "my-snapshot"
1102
+ # snapshot.name #=> "projects/my-project/snapshots/my-snapshot"
1103
+ #
1104
+ # @example Without providing a name:
1105
+ # require "google/cloud/pubsub"
1106
+ #
1107
+ # pubsub = Google::Cloud::PubSub.new
1108
+ # sub = pubsub.subscription "my-sub"
1109
+ #
1110
+ # snapshot = sub.create_snapshot
1111
+ # snapshot.name #=> "projects/my-project/snapshots/gcr-analysis-..."
1112
+ #
1113
+ def create_snapshot snapshot_name = nil, labels: nil
1114
+ ensure_service!
1115
+ grpc = service.create_snapshot name, snapshot_name, labels: labels
1116
+ Snapshot.from_grpc grpc, service
1117
+ end
1118
+ alias new_snapshot create_snapshot
1119
+
1120
+ ##
1121
+ # Resets the subscription's backlog to a given {Snapshot} or to a point
1122
+ # in time, whichever is provided in the request.
1123
+ #
1124
+ # @param [Snapshot, String, Time] snapshot The `Snapshot` instance,
1125
+ # snapshot name, or time to which to perform the seek.
1126
+ # If the argument is a snapshot, the snapshot's topic must be the
1127
+ # same as that of the subscription. If it is a time, messages retained
1128
+ # in the subscription that were published before this time are marked
1129
+ # as acknowledged, and messages retained in the subscription that were
1130
+ # published after this time are marked as unacknowledged. Note that
1131
+ # this operation affects only those messages retained in the
1132
+ # subscription. For example, if the time corresponds to a point before
1133
+ # the message retention window (or to a point before the system's
1134
+ # notion of the subscription creation time), only retained messages
1135
+ # will be marked as unacknowledged, and already-expunged messages will
1136
+ # not be restored.
1137
+ #
1138
+ # @return [Boolean] Returns `true` if the seek was successful.
1139
+ #
1140
+ # @example Using a snapshot
1141
+ # require "google/cloud/pubsub"
1142
+ #
1143
+ # pubsub = Google::Cloud::PubSub.new
1144
+ # sub = pubsub.subscription "my-sub"
1145
+ #
1146
+ # snapshot = sub.create_snapshot
1147
+ #
1148
+ # received_messages = sub.pull immediate: false
1149
+ # sub.acknowledge received_messages
1150
+ #
1151
+ # sub.seek snapshot
1152
+ #
1153
+ # @example Using a time:
1154
+ # require "google/cloud/pubsub"
1155
+ #
1156
+ # pubsub = Google::Cloud::PubSub.new
1157
+ # sub = pubsub.subscription "my-sub"
1158
+ #
1159
+ # time = Time.now
1160
+ #
1161
+ # received_messages = sub.pull immediate: false
1162
+ # sub.acknowledge received_messages
1163
+ #
1164
+ # sub.seek time
1165
+ #
1166
+ def seek snapshot
1167
+ ensure_service!
1168
+ service.seek name, snapshot
1169
+ true
1170
+ end
1171
+
1172
+ ##
1173
+ # Determines whether the subscription object was created without
1174
+ # retrieving the resource representation from the Pub/Sub service.
1175
+ #
1176
+ # @return [Boolean] `true` when the subscription was created without a
1177
+ # resource representation, `false` otherwise.
1178
+ #
1179
+ # @example
1180
+ # require "google/cloud/pubsub"
1181
+ #
1182
+ # pubsub = Google::Cloud::PubSub.new
1183
+ #
1184
+ # sub = pubsub.get_subscription "my-topic-sub", skip_lookup: true
1185
+ # sub.reference? #=> true
1186
+ #
1187
+ def reference?
1188
+ @grpc.nil?
1189
+ end
1190
+
1191
+ ##
1192
+ # Determines whether the subscription object was created with a resource
1193
+ # representation from the Pub/Sub service.
1194
+ #
1195
+ # @return [Boolean] `true` when the subscription was created with a
1196
+ # resource representation, `false` otherwise.
1197
+ #
1198
+ # @example
1199
+ # require "google/cloud/pubsub"
1200
+ #
1201
+ # pubsub = Google::Cloud::PubSub.new
1202
+ #
1203
+ # sub = pubsub.get_subscription "my-topic-sub"
1204
+ # sub.resource? #=> true
1205
+ #
1206
+ def resource?
1207
+ !@grpc.nil?
1208
+ end
1209
+
1210
+ ##
1211
+ # Reloads the subscription with current data from the Pub/Sub service.
1212
+ #
1213
+ # @return [Google::Cloud::PubSub::Subscription] Returns the reloaded
1214
+ # subscription
1215
+ #
1216
+ # @example
1217
+ # require "google/cloud/pubsub"
1218
+ #
1219
+ # pubsub = Google::Cloud::PubSub.new
1220
+ #
1221
+ # sub = pubsub.get_subscription "my-topic-sub"
1222
+ # sub.reload!
1223
+ #
1224
+ def reload!
1225
+ ensure_service!
1226
+ @grpc = service.get_subscription name
1227
+ @resource_name = nil
1228
+ self
1229
+ end
1230
+ alias refresh! reload!
1231
+
393
1232
  ##
394
1233
  # Gets the [Cloud IAM](https://cloud.google.com/iam/) access control
395
1234
  # policy for this subscription.
396
1235
  #
397
- # @see https://cloud.google.com/pubsub/reference/rpc/google.iam.v1#iampolicy
1236
+ # @see https://cloud.google.com/pubsub/docs/reference/rpc/google.iam.v1#iampolicy
398
1237
  # google.iam.v1.IAMPolicy
399
1238
  #
400
- # @param [Boolean] force Force the latest policy to be retrieved from
401
- # the Pub/Sub service when `true`. Otherwise the policy will be
402
- # memoized to reduce the number of API calls made to the Pub/Sub
403
- # service. The default is `false`.
404
- #
405
1239
  # @yield [policy] A block for updating the policy. The latest policy
406
1240
  # will be read from the Pub/Sub service and passed to the block. After
407
1241
  # the block completes, the modified policy will be written to the
@@ -411,83 +1245,68 @@ module Google
411
1245
  #
412
1246
  # @return [Policy] the current Cloud IAM Policy for this subscription
413
1247
  #
414
- # @example Policy values are memoized to reduce the number of API calls:
415
- # require "google/cloud"
416
- #
417
- # gcloud = Google::Cloud.new
418
- # pubsub = gcloud.pubsub
419
- # sub = pubsub.subscription "my-subscription"
420
- #
421
- # policy = sub.policy # API call
422
- # policy_2 = sub.policy # No API call
423
- #
424
- # @example Use `force` to retrieve the latest policy from the service:
425
- # require "google/cloud"
1248
+ # @example
1249
+ # require "google/cloud/pubsub"
426
1250
  #
427
- # gcloud = Google::Cloud.new
428
- # pubsub = gcloud.pubsub
1251
+ # pubsub = Google::Cloud::PubSub.new
429
1252
  # sub = pubsub.subscription "my-subscription"
430
1253
  #
431
- # policy = sub.policy force: true # API call
432
- # policy_2 = sub.policy force: true # API call
1254
+ # policy = sub.policy
433
1255
  #
434
1256
  # @example Update the policy by passing a block:
435
- # require "google/cloud"
1257
+ # require "google/cloud/pubsub"
436
1258
  #
437
- # gcloud = Google::Cloud.new
438
- # pubsub = gcloud.pubsub
1259
+ # pubsub = Google::Cloud::PubSub.new
439
1260
  # sub = pubsub.subscription "my-subscription"
440
1261
  #
441
- # policy = sub.policy do |p|
1262
+ # sub.policy do |p|
442
1263
  # p.add "roles/owner", "user:owner@example.com"
443
- # end # 2 API calls
444
- #
445
- def policy force: nil
446
- @policy = nil if force || block_given?
447
- @policy ||= begin
448
- ensure_service!
449
- grpc = service.get_subscription_policy name
450
- Policy.from_grpc grpc
451
- end
452
- return @policy unless block_given?
453
- p = @policy.deep_dup
454
- yield p
455
- self.policy = p
1264
+ # end
1265
+ #
1266
+ def policy
1267
+ ensure_service!
1268
+ grpc = service.get_subscription_policy name
1269
+ policy = Policy.from_grpc grpc
1270
+ return policy unless block_given?
1271
+ yield policy
1272
+ update_policy policy
456
1273
  end
457
1274
 
458
1275
  ##
459
1276
  # Updates the [Cloud IAM](https://cloud.google.com/iam/) access control
460
1277
  # policy for this subscription. The policy should be read from
461
- # {#policy}. See {Google::Cloud::Pubsub::Policy} for an explanation of
1278
+ # {#policy}. See {Google::Cloud::PubSub::Policy} for an explanation of
462
1279
  # the policy `etag` property and how to modify policies.
463
1280
  #
464
1281
  # You can also update the policy by passing a block to {#policy}, which
465
1282
  # will call this method internally after the block completes.
466
1283
  #
467
- # @see https://cloud.google.com/pubsub/reference/rpc/google.iam.v1#iampolicy
1284
+ # @see https://cloud.google.com/pubsub/docs/reference/rpc/google.iam.v1#iampolicy
468
1285
  # google.iam.v1.IAMPolicy
469
1286
  #
470
1287
  # @param [Policy] new_policy a new or modified Cloud IAM Policy for this
471
1288
  # subscription
472
1289
  #
1290
+ # @return [Policy] the policy returned by the API update operation
1291
+ #
473
1292
  # @example
474
- # require "google/cloud"
1293
+ # require "google/cloud/pubsub"
475
1294
  #
476
- # gcloud = Google::Cloud.new
477
- # pubsub = gcloud.pubsub
1295
+ # pubsub = Google::Cloud::PubSub.new
478
1296
  # sub = pubsub.subscription "my-subscription"
479
1297
  #
480
1298
  # policy = sub.policy # API call
481
1299
  #
482
1300
  # policy.add "roles/owner", "user:owner@example.com"
483
1301
  #
484
- # sub.policy = policy # API call
1302
+ # sub.update_policy policy # API call
485
1303
  #
486
- def policy= new_policy
1304
+ def update_policy new_policy
487
1305
  ensure_service!
488
1306
  grpc = service.set_subscription_policy name, new_policy.to_grpc
489
- @policy = Policy.from_grpc grpc
1307
+ Policy.from_grpc grpc
490
1308
  end
1309
+ alias policy= update_policy
491
1310
 
492
1311
  ##
493
1312
  # Tests the specified permissions against the [Cloud
@@ -512,10 +1331,9 @@ module Google
512
1331
  # @return [Array<String>] The permissions that have access.
513
1332
  #
514
1333
  # @example
515
- # require "google/cloud"
1334
+ # require "google/cloud/pubsub"
516
1335
  #
517
- # gcloud = Google::Cloud.new
518
- # pubsub = gcloud.pubsub
1336
+ # pubsub = Google::Cloud::PubSub.new
519
1337
  # sub = pubsub.subscription "my-subscription"
520
1338
  # perms = sub.test_permissions "pubsub.subscriptions.get",
521
1339
  # "pubsub.subscriptions.consume"
@@ -530,7 +1348,8 @@ module Google
530
1348
  end
531
1349
 
532
1350
  ##
533
- # @private New Subscription from a Google::Pubsub::V1::Subscription
1351
+ # @private
1352
+ # New Subscription from a Google::Cloud::PubSub::V1::Subscription
534
1353
  # object.
535
1354
  def self.from_grpc grpc, service
536
1355
  new.tap do |f|
@@ -539,21 +1358,30 @@ module Google
539
1358
  end
540
1359
  end
541
1360
 
1361
+ ##
1362
+ # @private New reference {Subscription} object without making an HTTP
1363
+ # request.
1364
+ def self.from_name name, service, options = {}
1365
+ name = service.subscription_path name, options
1366
+ from_grpc(nil, service).tap do |s|
1367
+ s.instance_variable_set :@resource_name, name
1368
+ end
1369
+ end
1370
+
542
1371
  protected
543
1372
 
544
1373
  ##
545
1374
  # @private Raise an error unless an active connection to the service is
546
1375
  # available.
547
1376
  def ensure_service!
548
- fail "Must have active connection to service" unless service
1377
+ raise "Must have active connection to service" unless service
549
1378
  end
550
1379
 
551
1380
  ##
552
- # Ensures a Google::Pubsub::V1::Subscription object exists.
1381
+ # Ensures a Google::Cloud::PubSub::V1::Subscription object exists.
553
1382
  def ensure_grpc!
554
1383
  ensure_service!
555
- return @grpc if @grpc
556
- @grpc = service.get_subscription @name
1384
+ reload! if reference?
557
1385
  end
558
1386
 
559
1387
  ##
@@ -566,5 +1394,7 @@ module Google
566
1394
  end
567
1395
  end
568
1396
  end
1397
+
1398
+ Pubsub = PubSub unless const_defined? :Pubsub
569
1399
  end
570
1400
  end