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.
- checksums.yaml +7 -0
- data/.yardopts +18 -0
- data/AUTHENTICATION.md +177 -0
- data/CHANGELOG.md +538 -0
- data/CODE_OF_CONDUCT.md +40 -0
- data/CONTRIBUTING.md +188 -0
- data/EMULATOR.md +37 -0
- data/LICENSE +201 -0
- data/LOGGING.md +32 -0
- data/OVERVIEW.md +557 -0
- data/TROUBLESHOOTING.md +31 -0
- data/lib/google-cloud-pubsub.rb +139 -0
- data/lib/google/cloud/pubsub.rb +173 -0
- data/lib/google/cloud/pubsub/async_publisher.rb +399 -0
- data/lib/google/cloud/pubsub/async_publisher/batch.rb +309 -0
- data/lib/google/cloud/pubsub/batch_publisher.rb +99 -0
- data/lib/google/cloud/pubsub/convert.rb +91 -0
- data/lib/google/cloud/pubsub/credentials.rb +47 -0
- data/lib/google/cloud/pubsub/errors.rb +85 -0
- data/lib/google/cloud/pubsub/message.rb +158 -0
- data/lib/google/cloud/pubsub/policy.rb +187 -0
- data/lib/google/cloud/pubsub/project.rb +393 -0
- data/lib/google/cloud/pubsub/publish_result.rb +103 -0
- data/lib/google/cloud/pubsub/received_message.rb +297 -0
- data/lib/google/cloud/pubsub/retry_policy.rb +90 -0
- data/lib/google/cloud/pubsub/service.rb +514 -0
- data/lib/google/cloud/pubsub/snapshot.rb +202 -0
- data/lib/google/cloud/pubsub/snapshot/list.rb +178 -0
- data/lib/google/cloud/pubsub/subscriber.rb +399 -0
- data/lib/google/cloud/pubsub/subscriber/enumerator_queue.rb +54 -0
- data/lib/google/cloud/pubsub/subscriber/inventory.rb +166 -0
- data/lib/google/cloud/pubsub/subscriber/sequencer.rb +115 -0
- data/lib/google/cloud/pubsub/subscriber/stream.rb +401 -0
- data/lib/google/cloud/pubsub/subscriber/timed_unary_buffer.rb +231 -0
- data/lib/google/cloud/pubsub/subscription.rb +1279 -0
- data/lib/google/cloud/pubsub/subscription/list.rb +205 -0
- data/lib/google/cloud/pubsub/subscription/push_config.rb +244 -0
- data/lib/google/cloud/pubsub/topic.rb +934 -0
- data/lib/google/cloud/pubsub/topic/list.rb +171 -0
- data/lib/google/cloud/pubsub/v1.rb +17 -0
- data/lib/google/cloud/pubsub/v1/credentials.rb +41 -0
- data/lib/google/cloud/pubsub/v1/doc/google/iam/v1/iam_policy.rb +21 -0
- data/lib/google/cloud/pubsub/v1/doc/google/iam/v1/options.rb +21 -0
- data/lib/google/cloud/pubsub/v1/doc/google/iam/v1/policy.rb +21 -0
- data/lib/google/cloud/pubsub/v1/doc/google/protobuf/duration.rb +91 -0
- data/lib/google/cloud/pubsub/v1/doc/google/protobuf/empty.rb +29 -0
- data/lib/google/cloud/pubsub/v1/doc/google/protobuf/field_mask.rb +222 -0
- data/lib/google/cloud/pubsub/v1/doc/google/protobuf/timestamp.rb +113 -0
- data/lib/google/cloud/pubsub/v1/doc/google/pubsub/v1/pubsub.rb +833 -0
- data/lib/google/cloud/pubsub/v1/doc/google/type/expr.rb +19 -0
- data/lib/google/cloud/pubsub/v1/publisher_client.rb +928 -0
- data/lib/google/cloud/pubsub/v1/publisher_client_config.json +120 -0
- data/lib/google/cloud/pubsub/v1/subscriber_client.rb +1466 -0
- data/lib/google/cloud/pubsub/v1/subscriber_client_config.json +153 -0
- data/lib/google/cloud/pubsub/version.rb +24 -0
- data/lib/google/pubsub/v1/pubsub_pb.rb +269 -0
- data/lib/google/pubsub/v1/pubsub_services_pb.rb +215 -0
- metadata +337 -0
@@ -0,0 +1,297 @@
|
|
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/errors"
|
17
|
+
require "google/cloud/pubsub/message"
|
18
|
+
|
19
|
+
module Google
|
20
|
+
module Cloud
|
21
|
+
module PubSub
|
22
|
+
##
|
23
|
+
# # ReceivedMessage
|
24
|
+
#
|
25
|
+
# Represents a Pub/Sub {Message} that can be acknowledged or delayed.
|
26
|
+
#
|
27
|
+
# @example
|
28
|
+
# require "google/cloud/pubsub"
|
29
|
+
#
|
30
|
+
# pubsub = Google::Cloud::PubSub.new
|
31
|
+
#
|
32
|
+
# sub = pubsub.subscription "my-topic-sub"
|
33
|
+
# subscriber = sub.listen do |received_message|
|
34
|
+
# puts received_message.message.data
|
35
|
+
# received_message.acknowledge!
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# # Start background threads that will call the block passed to listen.
|
39
|
+
# subscriber.start
|
40
|
+
#
|
41
|
+
# # Shut down the subscriber when ready to stop receiving messages.
|
42
|
+
# subscriber.stop.wait!
|
43
|
+
#
|
44
|
+
class ReceivedMessage
|
45
|
+
##
|
46
|
+
# @private The {Subscription} object.
|
47
|
+
attr_accessor :subscription
|
48
|
+
|
49
|
+
##
|
50
|
+
# @private The gRPC Google::Cloud::PubSub::V1::ReceivedMessage object.
|
51
|
+
attr_accessor :grpc
|
52
|
+
|
53
|
+
##
|
54
|
+
# @private Create an empty {Subscription} object.
|
55
|
+
def initialize
|
56
|
+
@subscription = nil
|
57
|
+
@grpc = Google::Cloud::PubSub::V1::ReceivedMessage.new
|
58
|
+
end
|
59
|
+
|
60
|
+
##
|
61
|
+
# The acknowledgment ID for the message.
|
62
|
+
def ack_id
|
63
|
+
@grpc.ack_id
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
# Returns the delivery attempt counter for the message. If a dead letter policy is not set on the subscription,
|
68
|
+
# this will be `nil`. See {Topic#subscribe}, {Subscription#dead_letter_topic=} and
|
69
|
+
# {Subscription#dead_letter_max_delivery_attempts=}.
|
70
|
+
#
|
71
|
+
# The delivery attempt counter is `1 + (the sum of number of NACKs and number of ack_deadline exceeds)` for the
|
72
|
+
# message.
|
73
|
+
#
|
74
|
+
# A NACK is any call to `ModifyAckDeadline` with a `0` deadline. An `ack_deadline` exceeds event is whenever a
|
75
|
+
# message is not acknowledged within `ack_deadline`. Note that `ack_deadline` is initially
|
76
|
+
# `Subscription.ackDeadlineSeconds`, but may get extended automatically by the client library.
|
77
|
+
#
|
78
|
+
# The first delivery of a given message will have this value as `1`. The value is calculated at best effort and
|
79
|
+
# is approximate.
|
80
|
+
#
|
81
|
+
# @return [Integer, nil] A delivery attempt value of `1` or greater, or `nil` if a dead letter policy is not set
|
82
|
+
# on the subscription.
|
83
|
+
#
|
84
|
+
# @example
|
85
|
+
# require "google/cloud/pubsub"
|
86
|
+
#
|
87
|
+
# pubsub = Google::Cloud::PubSub.new
|
88
|
+
#
|
89
|
+
# topic = pubsub.topic "my-topic"
|
90
|
+
# dead_letter_topic = pubsub.topic "my-dead-letter-topic", skip_lookup: true
|
91
|
+
# sub = topic.subscribe "my-topic-sub",
|
92
|
+
# dead_letter_topic: dead_letter_topic,
|
93
|
+
# dead_letter_max_delivery_attempts: 10
|
94
|
+
#
|
95
|
+
# subscriber = sub.listen do |received_message|
|
96
|
+
# puts received_message.message.delivery_attempt
|
97
|
+
# end
|
98
|
+
#
|
99
|
+
def delivery_attempt
|
100
|
+
return nil if @grpc.delivery_attempt && @grpc.delivery_attempt < 1
|
101
|
+
@grpc.delivery_attempt
|
102
|
+
end
|
103
|
+
|
104
|
+
##
|
105
|
+
# The received message.
|
106
|
+
def message
|
107
|
+
Message.from_grpc @grpc.message
|
108
|
+
end
|
109
|
+
alias msg message
|
110
|
+
|
111
|
+
##
|
112
|
+
# The received message payload. This data is a list of bytes encoded as
|
113
|
+
# ASCII-8BIT.
|
114
|
+
def data
|
115
|
+
message.data
|
116
|
+
end
|
117
|
+
|
118
|
+
##
|
119
|
+
# Optional attributes for the received message.
|
120
|
+
def attributes
|
121
|
+
message.attributes
|
122
|
+
end
|
123
|
+
|
124
|
+
##
|
125
|
+
# The ID of the received message, assigned by the server at publication
|
126
|
+
# time. Guaranteed to be unique within the topic.
|
127
|
+
def message_id
|
128
|
+
message.message_id
|
129
|
+
end
|
130
|
+
alias msg_id message_id
|
131
|
+
|
132
|
+
##
|
133
|
+
# Identifies related messages for which publish order should be
|
134
|
+
# respected.
|
135
|
+
#
|
136
|
+
# Google Cloud Pub/Sub ordering keys provide the ability to ensure
|
137
|
+
# related messages are sent to subscribers in the order in which they
|
138
|
+
# were published. Messages can be tagged with an ordering key, a string
|
139
|
+
# that identifies related messages for which publish order should be
|
140
|
+
# respected. The service guarantees that, for a given ordering key and
|
141
|
+
# publisher, messages are sent to subscribers in the order in which they
|
142
|
+
# were published. Ordering does not require sacrificing high throughput
|
143
|
+
# or scalability, as the service automatically distributes messages for
|
144
|
+
# different ordering keys across subscribers.
|
145
|
+
#
|
146
|
+
# See {Topic#publish_async} and {Subscription#listen}.
|
147
|
+
#
|
148
|
+
# @return [String]
|
149
|
+
#
|
150
|
+
def ordering_key
|
151
|
+
message.ordering_key
|
152
|
+
end
|
153
|
+
|
154
|
+
##
|
155
|
+
# The time at which the message was published.
|
156
|
+
def published_at
|
157
|
+
message.published_at
|
158
|
+
end
|
159
|
+
alias publish_time published_at
|
160
|
+
|
161
|
+
##
|
162
|
+
# Acknowledges receipt of the message.
|
163
|
+
#
|
164
|
+
# @example
|
165
|
+
# require "google/cloud/pubsub"
|
166
|
+
#
|
167
|
+
# pubsub = Google::Cloud::PubSub.new
|
168
|
+
#
|
169
|
+
# sub = pubsub.subscription "my-topic-sub"
|
170
|
+
# subscriber = sub.listen do |received_message|
|
171
|
+
# puts received_message.message.data
|
172
|
+
#
|
173
|
+
# received_message.acknowledge!
|
174
|
+
# end
|
175
|
+
#
|
176
|
+
# # Start background threads that will call block passed to listen.
|
177
|
+
# subscriber.start
|
178
|
+
#
|
179
|
+
# # Shut down the subscriber when ready to stop receiving messages.
|
180
|
+
# subscriber.stop.wait!
|
181
|
+
#
|
182
|
+
def acknowledge!
|
183
|
+
ensure_subscription!
|
184
|
+
subscription.acknowledge ack_id
|
185
|
+
end
|
186
|
+
alias ack! acknowledge!
|
187
|
+
|
188
|
+
##
|
189
|
+
# Modifies the acknowledge deadline for the message.
|
190
|
+
#
|
191
|
+
# This indicates that more time is needed to process the message, or to
|
192
|
+
# make the message available for redelivery.
|
193
|
+
#
|
194
|
+
# @param [Integer] new_deadline The new ack deadline in seconds from the
|
195
|
+
# time this request is sent to the Pub/Sub system. Must be >= 0. For
|
196
|
+
# example, if the value is `10`, the new ack deadline will expire 10
|
197
|
+
# seconds after the call is made. Specifying `0` may immediately make
|
198
|
+
# the message available for another pull request.
|
199
|
+
#
|
200
|
+
# @example
|
201
|
+
# require "google/cloud/pubsub"
|
202
|
+
#
|
203
|
+
# pubsub = Google::Cloud::PubSub.new
|
204
|
+
#
|
205
|
+
# sub = pubsub.subscription "my-topic-sub"
|
206
|
+
# subscriber = sub.listen do |received_message|
|
207
|
+
# puts received_message.message.data
|
208
|
+
#
|
209
|
+
# # Delay for 2 minutes
|
210
|
+
# received_message.modify_ack_deadline! 120
|
211
|
+
# end
|
212
|
+
#
|
213
|
+
# # Start background threads that will call block passed to listen.
|
214
|
+
# subscriber.start
|
215
|
+
#
|
216
|
+
# # Shut down the subscriber when ready to stop receiving messages.
|
217
|
+
# subscriber.stop.wait!
|
218
|
+
#
|
219
|
+
def modify_ack_deadline! new_deadline
|
220
|
+
ensure_subscription!
|
221
|
+
subscription.modify_ack_deadline new_deadline, ack_id
|
222
|
+
end
|
223
|
+
|
224
|
+
##
|
225
|
+
# Resets the acknowledge deadline for the message without acknowledging
|
226
|
+
# it.
|
227
|
+
#
|
228
|
+
# This will make the message available for redelivery.
|
229
|
+
#
|
230
|
+
# @example
|
231
|
+
# require "google/cloud/pubsub"
|
232
|
+
#
|
233
|
+
# pubsub = Google::Cloud::PubSub.new
|
234
|
+
#
|
235
|
+
# sub = pubsub.subscription "my-topic-sub"
|
236
|
+
# subscriber = sub.listen do |received_message|
|
237
|
+
# puts received_message.message.data
|
238
|
+
#
|
239
|
+
# # Release message back to the API.
|
240
|
+
# received_message.reject!
|
241
|
+
# end
|
242
|
+
#
|
243
|
+
# # Start background threads that will call block passed to listen.
|
244
|
+
# subscriber.start
|
245
|
+
#
|
246
|
+
# # Shut down the subscriber when ready to stop receiving messages.
|
247
|
+
# subscriber.stop.wait!
|
248
|
+
#
|
249
|
+
def reject!
|
250
|
+
modify_ack_deadline! 0
|
251
|
+
end
|
252
|
+
alias nack! reject!
|
253
|
+
alias ignore! reject!
|
254
|
+
|
255
|
+
# @private
|
256
|
+
def hash
|
257
|
+
@grpc.hash
|
258
|
+
end
|
259
|
+
|
260
|
+
# @private
|
261
|
+
def eql? other
|
262
|
+
return false unless other.is_a? self.class
|
263
|
+
@grpc.hash == other.hash
|
264
|
+
end
|
265
|
+
# @private
|
266
|
+
alias == eql?
|
267
|
+
|
268
|
+
# @private
|
269
|
+
def <=> other
|
270
|
+
return nil unless other.is_a? self.class
|
271
|
+
other_grpc = other.instance_variable_get :@grpc
|
272
|
+
@grpc <=> other_grpc
|
273
|
+
end
|
274
|
+
|
275
|
+
##
|
276
|
+
# @private New ReceivedMessage from a
|
277
|
+
# Google::Cloud::PubSub::V1::ReceivedMessage object.
|
278
|
+
def self.from_grpc grpc, subscription
|
279
|
+
new.tap do |rm|
|
280
|
+
rm.grpc = grpc
|
281
|
+
rm.subscription = subscription
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
protected
|
286
|
+
|
287
|
+
##
|
288
|
+
# Raise an error unless an active subscription is available.
|
289
|
+
def ensure_subscription!
|
290
|
+
raise "Must have active subscription" unless subscription
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
Pubsub = PubSub unless const_defined? :Pubsub
|
296
|
+
end
|
297
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# Copyright 2016 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/errors"
|
17
|
+
|
18
|
+
module Google
|
19
|
+
module Cloud
|
20
|
+
module PubSub
|
21
|
+
##
|
22
|
+
# # RetryPolicy
|
23
|
+
#
|
24
|
+
# An immutable Retry Policy value object that specifies how Cloud Pub/Sub retries message delivery.
|
25
|
+
#
|
26
|
+
# Retry delay will be exponential based on provided minimum and maximum backoffs. (See [Exponential
|
27
|
+
# backoff](https://en.wikipedia.org/wiki/Exponential_backoff).)
|
28
|
+
#
|
29
|
+
# Retry Policy will be triggered on NACKs or acknowledgement deadline exceeded events for a given message.
|
30
|
+
#
|
31
|
+
# Retry Policy is implemented on a best effort basis. At times, the delay between consecutive deliveries may not
|
32
|
+
# match the configuration. That is, delay can be more or less than configured backoff.
|
33
|
+
#
|
34
|
+
# **EXPERIMENTAL:** This API might be changed in backward-incompatible ways and is not recommended for production
|
35
|
+
# use. It is not subject to any SLA or deprecation policy.
|
36
|
+
#
|
37
|
+
# @attr [Numeric] minimum_backoff The minimum delay between consecutive deliveries of a given message. Value
|
38
|
+
# should be between 0 and 600 seconds. The default value is 10 seconds.
|
39
|
+
# @attr [Numeric] maximum_backoff The maximum delay between consecutive deliveries of a given message. Value
|
40
|
+
# should be between 0 and 600 seconds. The default value is 600 seconds.
|
41
|
+
#
|
42
|
+
# @example
|
43
|
+
# require "google/cloud/pubsub"
|
44
|
+
#
|
45
|
+
# pubsub = Google::Cloud::PubSub.new
|
46
|
+
#
|
47
|
+
# sub = pubsub.subscription "my-topic-sub"
|
48
|
+
#
|
49
|
+
# sub.retry_policy = Google::Cloud::PubSub::RetryPolicy.new minimum_backoff: 5, maximum_backoff: 300
|
50
|
+
#
|
51
|
+
# sub.retry_policy.minimum_backoff #=> 5
|
52
|
+
# sub.retry_policy.maximum_backoff #=> 300
|
53
|
+
#
|
54
|
+
class RetryPolicy
|
55
|
+
attr_reader :minimum_backoff, :maximum_backoff
|
56
|
+
|
57
|
+
##
|
58
|
+
# Creates a new, immutable RetryPolicy value object.
|
59
|
+
#
|
60
|
+
# @attr [Numeric, nil] minimum_backoff The minimum delay between consecutive deliveries of a given message.
|
61
|
+
# Value should be between 0 and 600 seconds. If `nil` is provided, the default value is 10 seconds.
|
62
|
+
# @attr [Numeric, nil] maximum_backoff The maximum delay between consecutive deliveries of a given message.
|
63
|
+
# Value should be between 0 and 600 seconds. If `nil` is provided, the default value is 600 seconds.
|
64
|
+
#
|
65
|
+
def initialize minimum_backoff: nil, maximum_backoff: nil
|
66
|
+
@minimum_backoff = minimum_backoff
|
67
|
+
@maximum_backoff = maximum_backoff
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# @private Convert the RetryPolicy to a Google::Cloud::PubSub::V1::RetryPolicy object.
|
72
|
+
def to_grpc
|
73
|
+
Google::Cloud::PubSub::V1::RetryPolicy.new(
|
74
|
+
minimum_backoff: Convert.number_to_duration(minimum_backoff),
|
75
|
+
maximum_backoff: Convert.number_to_duration(maximum_backoff)
|
76
|
+
)
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
# @private New RetryPolicy from a Google::Cloud::PubSub::V1::RetryPolicy object.
|
81
|
+
def self.from_grpc grpc
|
82
|
+
new(
|
83
|
+
minimum_backoff: Convert.duration_to_number(grpc.minimum_backoff),
|
84
|
+
maximum_backoff: Convert.duration_to_number(grpc.maximum_backoff)
|
85
|
+
)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,514 @@
|
|
1
|
+
# Copyright 2016 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/errors"
|
17
|
+
require "google/cloud/pubsub/credentials"
|
18
|
+
require "google/cloud/pubsub/convert"
|
19
|
+
require "google/cloud/pubsub/version"
|
20
|
+
require "google/cloud/pubsub/v1"
|
21
|
+
require "google/gax/errors"
|
22
|
+
require "securerandom"
|
23
|
+
|
24
|
+
module Google
|
25
|
+
module Cloud
|
26
|
+
module PubSub
|
27
|
+
##
|
28
|
+
# @private Represents the GAX Pub/Sub service, including all the API
|
29
|
+
# methods.
|
30
|
+
class Service
|
31
|
+
attr_accessor :project, :credentials, :host, :timeout, :client_config
|
32
|
+
###
|
33
|
+
# The same client_id is used across all streaming pull connections that are created by this client. This is
|
34
|
+
# intentional, as it indicates to the server that any guarantees, such as message ordering, made for a stream
|
35
|
+
# that is disconnected will be made for the stream that is created to replace it. The attr_accessor allows the
|
36
|
+
# value to be replaced for unit testing.
|
37
|
+
attr_accessor :client_id
|
38
|
+
|
39
|
+
##
|
40
|
+
# Creates a new Service instance.
|
41
|
+
def initialize project, credentials, host: nil, timeout: nil,
|
42
|
+
client_config: nil
|
43
|
+
@project = project
|
44
|
+
@credentials = credentials
|
45
|
+
@host = host || V1::PublisherClient::SERVICE_ADDRESS
|
46
|
+
@timeout = timeout
|
47
|
+
@client_config = client_config || {}
|
48
|
+
@client_id = SecureRandom.uuid.freeze
|
49
|
+
end
|
50
|
+
|
51
|
+
def channel
|
52
|
+
require "grpc"
|
53
|
+
GRPC::Core::Channel.new host, chan_args, chan_creds
|
54
|
+
end
|
55
|
+
|
56
|
+
def chan_args
|
57
|
+
{ "grpc.max_send_message_length" => -1,
|
58
|
+
"grpc.max_receive_message_length" => -1,
|
59
|
+
"grpc.keepalive_time_ms" => 300_000,
|
60
|
+
"grpc.service_config_disable_resolution" => 1 }
|
61
|
+
end
|
62
|
+
|
63
|
+
def chan_creds
|
64
|
+
return credentials if insecure?
|
65
|
+
require "grpc"
|
66
|
+
GRPC::Core::ChannelCredentials.new.compose GRPC::Core::CallCredentials.new credentials.client.updater_proc
|
67
|
+
end
|
68
|
+
|
69
|
+
def subscriber
|
70
|
+
return mocked_subscriber if mocked_subscriber
|
71
|
+
@subscriber ||= begin
|
72
|
+
V1::SubscriberClient.new(
|
73
|
+
credentials: channel,
|
74
|
+
timeout: timeout,
|
75
|
+
client_config: client_config,
|
76
|
+
lib_name: "gccl",
|
77
|
+
lib_version: Google::Cloud::PubSub::VERSION
|
78
|
+
)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
attr_accessor :mocked_subscriber
|
82
|
+
|
83
|
+
def publisher
|
84
|
+
return mocked_publisher if mocked_publisher
|
85
|
+
@publisher ||= begin
|
86
|
+
V1::PublisherClient.new(
|
87
|
+
credentials: channel,
|
88
|
+
timeout: timeout,
|
89
|
+
client_config: client_config,
|
90
|
+
lib_name: "gccl",
|
91
|
+
lib_version: Google::Cloud::PubSub::VERSION
|
92
|
+
)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
attr_accessor :mocked_publisher
|
96
|
+
|
97
|
+
def insecure?
|
98
|
+
credentials == :this_channel_is_insecure
|
99
|
+
end
|
100
|
+
|
101
|
+
##
|
102
|
+
# Gets the configuration of a topic.
|
103
|
+
# Since the topic only has the name attribute,
|
104
|
+
# this method is only useful to check the existence of a topic.
|
105
|
+
# If other attributes are added in the future,
|
106
|
+
# they will be returned here.
|
107
|
+
def get_topic topic_name, options = {}
|
108
|
+
execute do
|
109
|
+
publisher.get_topic topic_path(topic_name, options),
|
110
|
+
options: default_options
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
##
|
115
|
+
# Lists matching topics.
|
116
|
+
def list_topics options = {}
|
117
|
+
call_options = default_options
|
118
|
+
if (token = options[:token])
|
119
|
+
call_options = Google::Gax::CallOptions.new(
|
120
|
+
kwargs: default_headers,
|
121
|
+
page_token: token
|
122
|
+
)
|
123
|
+
end
|
124
|
+
|
125
|
+
execute do
|
126
|
+
paged_enum = publisher.list_topics project_path(options),
|
127
|
+
page_size: options[:max],
|
128
|
+
options: call_options
|
129
|
+
|
130
|
+
paged_enum.page.response
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
##
|
135
|
+
# Creates the given topic with the given name.
|
136
|
+
def create_topic topic_name, labels: nil, kms_key_name: nil, persistence_regions: nil, options: {}
|
137
|
+
if persistence_regions
|
138
|
+
message_storage_policy = {
|
139
|
+
allowed_persistence_regions: Array(persistence_regions)
|
140
|
+
}
|
141
|
+
end
|
142
|
+
|
143
|
+
execute do
|
144
|
+
publisher.create_topic \
|
145
|
+
topic_path(topic_name, options),
|
146
|
+
labels: labels,
|
147
|
+
kms_key_name: kms_key_name,
|
148
|
+
message_storage_policy: message_storage_policy,
|
149
|
+
options: default_options
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def update_topic topic_obj, *fields
|
154
|
+
mask = Google::Protobuf::FieldMask.new paths: fields.map(&:to_s)
|
155
|
+
execute do
|
156
|
+
publisher.update_topic topic_obj, mask, options: default_options
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
##
|
161
|
+
# Deletes the topic with the given name. All subscriptions to this topic
|
162
|
+
# are also deleted. Raises GRPC status code 5 if the topic does not
|
163
|
+
# exist. After a topic is deleted, a new topic may be created with the
|
164
|
+
# same name.
|
165
|
+
def delete_topic topic_name
|
166
|
+
execute do
|
167
|
+
publisher.delete_topic topic_path(topic_name),
|
168
|
+
options: default_options
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
##
|
173
|
+
# Adds one or more messages to the topic.
|
174
|
+
# Raises GRPC status code 5 if the topic does not exist.
|
175
|
+
# The messages parameter is an array of arrays.
|
176
|
+
# The first element is the data, second is attributes hash.
|
177
|
+
def publish topic, messages
|
178
|
+
execute do
|
179
|
+
publisher.publish topic_path(topic), messages,
|
180
|
+
options: default_options
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
##
|
185
|
+
# Gets the details of a subscription.
|
186
|
+
def get_subscription subscription_name, options = {}
|
187
|
+
subscription = subscription_path subscription_name, options
|
188
|
+
execute do
|
189
|
+
subscriber.get_subscription subscription, options: default_options
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
##
|
194
|
+
# Lists matching subscriptions by project and topic.
|
195
|
+
def list_topics_subscriptions topic, options = {}
|
196
|
+
call_options = default_options
|
197
|
+
if (token = options[:token])
|
198
|
+
call_options = Google::Gax::CallOptions.new(
|
199
|
+
kwargs: default_headers,
|
200
|
+
page_token: token
|
201
|
+
)
|
202
|
+
end
|
203
|
+
|
204
|
+
execute do
|
205
|
+
paged_enum = publisher.list_topic_subscriptions \
|
206
|
+
topic_path(topic, options),
|
207
|
+
page_size: options[:max],
|
208
|
+
options: call_options
|
209
|
+
|
210
|
+
paged_enum.page.response
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
##
|
215
|
+
# Lists matching subscriptions by project.
|
216
|
+
def list_subscriptions options = {}
|
217
|
+
call_options = default_options
|
218
|
+
if (token = options[:token])
|
219
|
+
call_options = Google::Gax::CallOptions.new(
|
220
|
+
kwargs: default_headers,
|
221
|
+
page_token: token
|
222
|
+
)
|
223
|
+
end
|
224
|
+
|
225
|
+
execute do
|
226
|
+
paged_enum = subscriber.list_subscriptions project_path(options),
|
227
|
+
page_size: options[:max],
|
228
|
+
options: call_options
|
229
|
+
|
230
|
+
paged_enum.page.response
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
##
|
235
|
+
# Creates a subscription on a given topic for a given subscriber.
|
236
|
+
def create_subscription topic, subscription_name, options = {}
|
237
|
+
name = subscription_path subscription_name, options
|
238
|
+
topic = topic_path topic
|
239
|
+
push_config = if options[:endpoint]
|
240
|
+
Google::Cloud::PubSub::V1::PushConfig.new \
|
241
|
+
push_endpoint: options[:endpoint],
|
242
|
+
attributes: (options[:attributes] || {}).to_h
|
243
|
+
end
|
244
|
+
mrd = Convert.number_to_duration options[:retention]
|
245
|
+
execute do
|
246
|
+
subscriber.create_subscription \
|
247
|
+
name, topic,
|
248
|
+
push_config: push_config,
|
249
|
+
ack_deadline_seconds: options[:deadline],
|
250
|
+
retain_acked_messages: options[:retain_acked],
|
251
|
+
message_retention_duration: mrd,
|
252
|
+
labels: options[:labels],
|
253
|
+
enable_message_ordering: options[:message_ordering],
|
254
|
+
filter: options[:filter],
|
255
|
+
dead_letter_policy: dead_letter_policy(options),
|
256
|
+
retry_policy: options[:retry_policy],
|
257
|
+
options: default_options
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
def update_subscription subscription_obj, *fields
|
262
|
+
mask = Google::Protobuf::FieldMask.new paths: fields.map(&:to_s)
|
263
|
+
execute do
|
264
|
+
subscriber.update_subscription subscription_obj, mask, options: default_options
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
##
|
269
|
+
# Deletes an existing subscription.
|
270
|
+
# All pending messages in the subscription are immediately dropped.
|
271
|
+
def delete_subscription subscription
|
272
|
+
execute do
|
273
|
+
subscriber.delete_subscription subscription_path(subscription),
|
274
|
+
options: default_options
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
##
|
279
|
+
# Pulls a single message from the server.
|
280
|
+
def pull subscription, options = {}
|
281
|
+
subscription = subscription_path subscription, options
|
282
|
+
max_messages = options.fetch(:max, 100).to_i
|
283
|
+
return_immediately = !(!options.fetch(:immediate, true))
|
284
|
+
|
285
|
+
execute do
|
286
|
+
subscriber.pull subscription,
|
287
|
+
max_messages,
|
288
|
+
return_immediately: return_immediately,
|
289
|
+
options: default_options
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
def streaming_pull request_enum
|
294
|
+
execute do
|
295
|
+
subscriber.streaming_pull request_enum, options: default_options
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
##
|
300
|
+
# Acknowledges receipt of a message.
|
301
|
+
def acknowledge subscription, *ack_ids
|
302
|
+
execute do
|
303
|
+
subscriber.acknowledge subscription_path(subscription), ack_ids,
|
304
|
+
options: default_options
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
##
|
309
|
+
# Modifies the PushConfig for a specified subscription.
|
310
|
+
def modify_push_config subscription, endpoint, attributes
|
311
|
+
subscription = subscription_path subscription
|
312
|
+
# Convert attributes to strings to match the protobuf definition
|
313
|
+
attributes = Hash[attributes.map { |k, v| [String(k), String(v)] }]
|
314
|
+
push_config = Google::Cloud::PubSub::V1::PushConfig.new(
|
315
|
+
push_endpoint: endpoint,
|
316
|
+
attributes: attributes
|
317
|
+
)
|
318
|
+
|
319
|
+
execute do
|
320
|
+
subscriber.modify_push_config subscription, push_config,
|
321
|
+
options: default_options
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
##
|
326
|
+
# Modifies the ack deadline for a specific message.
|
327
|
+
def modify_ack_deadline subscription, ids, deadline
|
328
|
+
execute do
|
329
|
+
subscriber.modify_ack_deadline subscription_path(subscription),
|
330
|
+
Array(ids),
|
331
|
+
deadline, options: default_options
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
##
|
336
|
+
# Lists snapshots by project.
|
337
|
+
def list_snapshots options = {}
|
338
|
+
call_options = default_options
|
339
|
+
if (token = options[:token])
|
340
|
+
call_options = Google::Gax::CallOptions.new(
|
341
|
+
kwargs: default_headers,
|
342
|
+
page_token: token
|
343
|
+
)
|
344
|
+
end
|
345
|
+
|
346
|
+
execute do
|
347
|
+
paged_enum = subscriber.list_snapshots project_path(options),
|
348
|
+
page_size: options[:max],
|
349
|
+
options: call_options
|
350
|
+
|
351
|
+
paged_enum.page.response
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
##
|
356
|
+
# Creates a snapshot on a given subscription.
|
357
|
+
def create_snapshot subscription, snapshot_name, labels: nil
|
358
|
+
name = snapshot_path snapshot_name
|
359
|
+
execute do
|
360
|
+
subscriber.create_snapshot name,
|
361
|
+
subscription_path(subscription),
|
362
|
+
labels: labels,
|
363
|
+
options: default_options
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
def update_snapshot snapshot_obj, *fields
|
368
|
+
mask = Google::Protobuf::FieldMask.new paths: fields.map(&:to_s)
|
369
|
+
execute do
|
370
|
+
subscriber.update_snapshot snapshot_obj, mask, options: default_options
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
##
|
375
|
+
# Deletes an existing snapshot.
|
376
|
+
# All pending messages in the snapshot are immediately dropped.
|
377
|
+
def delete_snapshot snapshot
|
378
|
+
execute do
|
379
|
+
subscriber.delete_snapshot snapshot_path(snapshot),
|
380
|
+
options: default_options
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
##
|
385
|
+
# Adjusts the given subscription to a time or snapshot.
|
386
|
+
def seek subscription, time_or_snapshot
|
387
|
+
subscription = subscription_path subscription
|
388
|
+
execute do
|
389
|
+
if a_time? time_or_snapshot
|
390
|
+
time = Convert.time_to_timestamp time_or_snapshot
|
391
|
+
subscriber.seek subscription, time: time, options: default_options
|
392
|
+
else
|
393
|
+
time_or_snapshot = time_or_snapshot.name if time_or_snapshot.is_a? Snapshot
|
394
|
+
subscriber.seek subscription,
|
395
|
+
snapshot: snapshot_path(time_or_snapshot),
|
396
|
+
options: default_options
|
397
|
+
end
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
def get_topic_policy topic_name, options = {}
|
402
|
+
execute do
|
403
|
+
publisher.get_iam_policy topic_path(topic_name, options),
|
404
|
+
options: default_options
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
def set_topic_policy topic_name, new_policy, options = {}
|
409
|
+
resource = topic_path topic_name, options
|
410
|
+
|
411
|
+
execute do
|
412
|
+
publisher.set_iam_policy resource, new_policy,
|
413
|
+
options: default_options
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
def test_topic_permissions topic_name, permissions, options = {}
|
418
|
+
resource = topic_path topic_name, options
|
419
|
+
|
420
|
+
execute do
|
421
|
+
publisher.test_iam_permissions resource, permissions,
|
422
|
+
options: default_options
|
423
|
+
end
|
424
|
+
end
|
425
|
+
|
426
|
+
def get_subscription_policy subscription_name, options = {}
|
427
|
+
resource = subscription_path subscription_name, options
|
428
|
+
|
429
|
+
execute do
|
430
|
+
subscriber.get_iam_policy resource, options: default_options
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
def set_subscription_policy subscription_name, new_policy, options = {}
|
435
|
+
resource = subscription_path subscription_name, options
|
436
|
+
|
437
|
+
execute do
|
438
|
+
subscriber.set_iam_policy resource, new_policy,
|
439
|
+
options: default_options
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
def test_subscription_permissions subscription_name,
|
444
|
+
permissions, options = {}
|
445
|
+
resource = subscription_path subscription_name, options
|
446
|
+
|
447
|
+
execute do
|
448
|
+
subscriber.test_iam_permissions resource, permissions,
|
449
|
+
options: default_options
|
450
|
+
end
|
451
|
+
end
|
452
|
+
|
453
|
+
def project_path options = {}
|
454
|
+
project_name = options[:project] || project
|
455
|
+
"projects/#{project_name}"
|
456
|
+
end
|
457
|
+
|
458
|
+
def topic_path topic_name, options = {}
|
459
|
+
return topic_name if topic_name.to_s.include? "/"
|
460
|
+
"#{project_path options}/topics/#{topic_name}"
|
461
|
+
end
|
462
|
+
|
463
|
+
def subscription_path subscription_name, options = {}
|
464
|
+
return subscription_name if subscription_name.to_s.include? "/"
|
465
|
+
"#{project_path options}/subscriptions/#{subscription_name}"
|
466
|
+
end
|
467
|
+
|
468
|
+
def snapshot_path snapshot_name, options = {}
|
469
|
+
return snapshot_name if snapshot_name.nil? || snapshot_name.to_s.include?("/")
|
470
|
+
"#{project_path options}/snapshots/#{snapshot_name}"
|
471
|
+
end
|
472
|
+
|
473
|
+
def inspect
|
474
|
+
"#<#{self.class.name} (#{@project})>"
|
475
|
+
end
|
476
|
+
|
477
|
+
protected
|
478
|
+
|
479
|
+
def a_time? obj
|
480
|
+
return false unless obj.respond_to? :to_time
|
481
|
+
# Rails' String#to_time returns nil if the string doesn't parse.
|
482
|
+
return false if obj.to_time.nil?
|
483
|
+
true
|
484
|
+
end
|
485
|
+
|
486
|
+
def dead_letter_policy options
|
487
|
+
return nil unless options[:dead_letter_topic_name]
|
488
|
+
policy = Google::Cloud::PubSub::V1::DeadLetterPolicy.new dead_letter_topic: options[:dead_letter_topic_name]
|
489
|
+
if options[:dead_letter_max_delivery_attempts]
|
490
|
+
policy.max_delivery_attempts = options[:dead_letter_max_delivery_attempts]
|
491
|
+
end
|
492
|
+
policy
|
493
|
+
end
|
494
|
+
|
495
|
+
def default_headers
|
496
|
+
{ "google-cloud-resource-prefix" => "projects/#{@project}" }
|
497
|
+
end
|
498
|
+
|
499
|
+
def default_options
|
500
|
+
Google::Gax::CallOptions.new kwargs: default_headers
|
501
|
+
end
|
502
|
+
|
503
|
+
def execute
|
504
|
+
yield
|
505
|
+
rescue Google::Gax::GaxError => e
|
506
|
+
# GaxError wraps BadStatus, but exposes it as #cause
|
507
|
+
raise Google::Cloud::Error.from_error(e.cause)
|
508
|
+
end
|
509
|
+
end
|
510
|
+
end
|
511
|
+
|
512
|
+
Pubsub = PubSub unless const_defined? :Pubsub
|
513
|
+
end
|
514
|
+
end
|