google-cloud-pubsub 1.9.0

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