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