google-cloud-pubsub 1.9.0

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