google-cloud-pubsub 0.26.0 → 2.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.yardopts +12 -2
- data/AUTHENTICATION.md +178 -0
- data/CHANGELOG.md +659 -0
- data/CODE_OF_CONDUCT.md +40 -0
- data/CONTRIBUTING.md +187 -0
- data/EMULATOR.md +37 -0
- data/LICENSE +2 -2
- data/LOGGING.md +32 -0
- data/OVERVIEW.md +528 -0
- data/TROUBLESHOOTING.md +31 -0
- data/lib/google/cloud/pubsub/async_publisher/batch.rb +310 -0
- data/lib/google/cloud/pubsub/async_publisher.rb +402 -0
- data/lib/google/cloud/pubsub/batch_publisher.rb +100 -0
- data/lib/google/cloud/pubsub/convert.rb +91 -0
- data/lib/google/cloud/pubsub/credentials.rb +26 -10
- data/lib/google/cloud/pubsub/errors.rb +85 -0
- data/lib/google/cloud/pubsub/message.rb +80 -17
- data/lib/google/cloud/pubsub/policy.rb +17 -14
- data/lib/google/cloud/pubsub/project.rb +364 -250
- data/lib/google/cloud/pubsub/publish_result.rb +103 -0
- data/lib/google/cloud/pubsub/received_message.rb +162 -24
- data/lib/google/cloud/pubsub/retry_policy.rb +88 -0
- data/lib/google/cloud/pubsub/schema/list.rb +180 -0
- data/lib/google/cloud/pubsub/schema.rb +310 -0
- data/lib/google/cloud/pubsub/service.rb +281 -265
- data/lib/google/cloud/pubsub/snapshot/list.rb +21 -21
- data/lib/google/cloud/pubsub/snapshot.rb +55 -15
- data/lib/google/cloud/pubsub/subscriber/enumerator_queue.rb +54 -0
- data/lib/google/cloud/pubsub/subscriber/inventory.rb +173 -0
- data/lib/google/cloud/pubsub/subscriber/sequencer.rb +115 -0
- data/lib/google/cloud/pubsub/subscriber/stream.rb +400 -0
- data/lib/google/cloud/pubsub/subscriber/timed_unary_buffer.rb +230 -0
- data/lib/google/cloud/pubsub/subscriber.rb +417 -0
- data/lib/google/cloud/pubsub/subscription/list.rb +28 -28
- data/lib/google/cloud/pubsub/subscription/push_config.rb +268 -0
- data/lib/google/cloud/pubsub/subscription.rb +900 -172
- data/lib/google/cloud/pubsub/topic/list.rb +21 -21
- data/lib/google/cloud/pubsub/topic.rb +674 -95
- data/lib/google/cloud/pubsub/version.rb +6 -4
- data/lib/google/cloud/pubsub.rb +104 -439
- data/lib/google-cloud-pubsub.rb +60 -29
- metadata +88 -50
- data/README.md +0 -69
- data/lib/google/cloud/pubsub/topic/publisher.rb +0 -86
- data/lib/google/cloud/pubsub/v1/doc/google/protobuf/duration.rb +0 -77
- data/lib/google/cloud/pubsub/v1/doc/google/protobuf/field_mask.rb +0 -223
- data/lib/google/cloud/pubsub/v1/doc/google/protobuf/timestamp.rb +0 -81
- data/lib/google/cloud/pubsub/v1/doc/google/pubsub/v1/pubsub.rb +0 -503
- data/lib/google/cloud/pubsub/v1/publisher_client.rb +0 -605
- data/lib/google/cloud/pubsub/v1/publisher_client_config.json +0 -96
- data/lib/google/cloud/pubsub/v1/subscriber_client.rb +0 -1104
- data/lib/google/cloud/pubsub/v1/subscriber_client_config.json +0 -127
- data/lib/google/cloud/pubsub/v1.rb +0 -17
- data/lib/google/pubsub/v1/pubsub_pb.rb +0 -187
- data/lib/google/pubsub/v1/pubsub_services_pb.rb +0 -159
@@ -0,0 +1,230 @@
|
|
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
|
29
|
+
attr_reader :interval
|
30
|
+
|
31
|
+
def initialize subscriber, max_bytes: 500_000, interval: 1.0
|
32
|
+
super() # to init MonitorMixin
|
33
|
+
|
34
|
+
@subscriber = subscriber
|
35
|
+
@max_bytes = max_bytes
|
36
|
+
@interval = interval
|
37
|
+
|
38
|
+
# Using a Hash ensures there is only one entry for each ack_id in
|
39
|
+
# the buffer. Adding an entry again will overwrite the previous
|
40
|
+
# entry.
|
41
|
+
@register = {}
|
42
|
+
|
43
|
+
@task = Concurrent::TimerTask.new execution_interval: interval do
|
44
|
+
flush!
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def acknowledge ack_ids
|
49
|
+
return if ack_ids.empty?
|
50
|
+
|
51
|
+
synchronize do
|
52
|
+
ack_ids.each do |ack_id|
|
53
|
+
# ack has no deadline set, use :ack indicate it is an ack
|
54
|
+
@register[ack_id] = :ack
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
true
|
59
|
+
end
|
60
|
+
|
61
|
+
def modify_ack_deadline deadline, ack_ids
|
62
|
+
return if ack_ids.empty?
|
63
|
+
|
64
|
+
synchronize do
|
65
|
+
ack_ids.each do |ack_id|
|
66
|
+
@register[ack_id] = deadline
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
true
|
71
|
+
end
|
72
|
+
|
73
|
+
def renew_lease deadline, ack_ids
|
74
|
+
return if ack_ids.empty?
|
75
|
+
|
76
|
+
synchronize do
|
77
|
+
ack_ids.each do |ack_id|
|
78
|
+
# Don't overwrite pending actions when renewing leased messages.
|
79
|
+
@register[ack_id] ||= deadline
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
true
|
84
|
+
end
|
85
|
+
|
86
|
+
def flush!
|
87
|
+
# Grab requests from the buffer and release synchronize ASAP
|
88
|
+
requests = flush_requests!
|
89
|
+
return if requests.empty?
|
90
|
+
|
91
|
+
# Perform the RCP calls concurrently
|
92
|
+
with_threadpool do |pool|
|
93
|
+
requests[:acknowledge].each do |ack_req|
|
94
|
+
add_future pool do
|
95
|
+
@subscriber.service.acknowledge ack_req.subscription, *ack_req.ack_ids
|
96
|
+
end
|
97
|
+
end
|
98
|
+
requests[:modify_ack_deadline].each do |mod_ack_req|
|
99
|
+
add_future pool do
|
100
|
+
@subscriber.service.modify_ack_deadline mod_ack_req.subscription, mod_ack_req.ack_ids,
|
101
|
+
mod_ack_req.ack_deadline_seconds
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
true
|
107
|
+
end
|
108
|
+
|
109
|
+
def start
|
110
|
+
@task.execute
|
111
|
+
|
112
|
+
self
|
113
|
+
end
|
114
|
+
|
115
|
+
def stop
|
116
|
+
@task.shutdown
|
117
|
+
flush!
|
118
|
+
|
119
|
+
self
|
120
|
+
end
|
121
|
+
|
122
|
+
def started?
|
123
|
+
@task.running?
|
124
|
+
end
|
125
|
+
|
126
|
+
def stopped?
|
127
|
+
!started?
|
128
|
+
end
|
129
|
+
|
130
|
+
private
|
131
|
+
|
132
|
+
def flush_requests!
|
133
|
+
prev_reg =
|
134
|
+
synchronize do
|
135
|
+
return {} if @register.empty?
|
136
|
+
reg = @register
|
137
|
+
@register = {}
|
138
|
+
reg
|
139
|
+
end
|
140
|
+
|
141
|
+
groups = prev_reg.each_pair.group_by { |_ack_id, delay| delay }
|
142
|
+
req_hash = groups.transform_values { |v| v.map(&:first) }
|
143
|
+
|
144
|
+
requests = { acknowledge: [] }
|
145
|
+
ack_ids = Array(req_hash.delete(:ack)) # ack has no deadline set
|
146
|
+
requests[:acknowledge] = create_acknowledge_requests ack_ids if ack_ids.any?
|
147
|
+
requests[:modify_ack_deadline] =
|
148
|
+
req_hash.map do |mod_deadline, mod_ack_ids|
|
149
|
+
create_modify_ack_deadline_requests mod_deadline, mod_ack_ids
|
150
|
+
end.flatten
|
151
|
+
requests
|
152
|
+
end
|
153
|
+
|
154
|
+
def create_acknowledge_requests ack_ids
|
155
|
+
req = Google::Cloud::PubSub::V1::AcknowledgeRequest.new(
|
156
|
+
subscription: subscription_name,
|
157
|
+
ack_ids: ack_ids
|
158
|
+
)
|
159
|
+
addl_to_create = req.to_proto.bytesize / max_bytes
|
160
|
+
return [req] if addl_to_create.zero?
|
161
|
+
|
162
|
+
ack_ids.each_slice(addl_to_create + 1).map do |sliced_ack_ids|
|
163
|
+
Google::Cloud::PubSub::V1::AcknowledgeRequest.new(
|
164
|
+
subscription: subscription_name,
|
165
|
+
ack_ids: sliced_ack_ids
|
166
|
+
)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def create_modify_ack_deadline_requests deadline, ack_ids
|
171
|
+
req = Google::Cloud::PubSub::V1::ModifyAckDeadlineRequest.new(
|
172
|
+
subscription: subscription_name,
|
173
|
+
ack_ids: ack_ids,
|
174
|
+
ack_deadline_seconds: deadline
|
175
|
+
)
|
176
|
+
addl_to_create = req.to_proto.bytesize / max_bytes
|
177
|
+
return [req] if addl_to_create.zero?
|
178
|
+
|
179
|
+
ack_ids.each_slice(addl_to_create + 1).map do |sliced_ack_ids|
|
180
|
+
Google::Cloud::PubSub::V1::ModifyAckDeadlineRequest.new(
|
181
|
+
subscription: subscription_name,
|
182
|
+
ack_ids: sliced_ack_ids,
|
183
|
+
ack_deadline_seconds: deadline
|
184
|
+
)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def subscription_name
|
189
|
+
@subscriber.subscription_name
|
190
|
+
end
|
191
|
+
|
192
|
+
def push_threads
|
193
|
+
@subscriber.push_threads
|
194
|
+
end
|
195
|
+
|
196
|
+
def error! error
|
197
|
+
@subscriber.error! error
|
198
|
+
end
|
199
|
+
|
200
|
+
def with_threadpool
|
201
|
+
pool = Concurrent::ThreadPoolExecutor.new max_threads: @subscriber.push_threads
|
202
|
+
|
203
|
+
yield pool
|
204
|
+
|
205
|
+
pool.shutdown
|
206
|
+
pool.wait_for_termination 60
|
207
|
+
return if pool.shutdown?
|
208
|
+
|
209
|
+
pool.kill
|
210
|
+
begin
|
211
|
+
raise "Timeout making subscriber API calls"
|
212
|
+
rescue StandardError => e
|
213
|
+
error! e
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def add_future pool
|
218
|
+
Concurrent::Promises.future_on pool do
|
219
|
+
yield
|
220
|
+
rescue StandardError => e
|
221
|
+
error! e
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
Pubsub = PubSub unless const_defined? :Pubsub
|
229
|
+
end
|
230
|
+
end
|
@@ -0,0 +1,417 @@
|
|
1
|
+
# Copyright 2017 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/service"
|
17
|
+
require "google/cloud/pubsub/subscriber/stream"
|
18
|
+
require "google/cloud/pubsub/subscriber/timed_unary_buffer"
|
19
|
+
require "monitor"
|
20
|
+
|
21
|
+
module Google
|
22
|
+
module Cloud
|
23
|
+
module PubSub
|
24
|
+
##
|
25
|
+
# Subscriber object used to stream and process messages from a
|
26
|
+
# Subscription. See {Google::Cloud::PubSub::Subscription#listen}
|
27
|
+
#
|
28
|
+
# @example
|
29
|
+
# require "google/cloud/pubsub"
|
30
|
+
#
|
31
|
+
# pubsub = Google::Cloud::PubSub.new
|
32
|
+
#
|
33
|
+
# sub = pubsub.subscription "my-topic-sub"
|
34
|
+
#
|
35
|
+
# subscriber = sub.listen do |received_message|
|
36
|
+
# # process message
|
37
|
+
# received_message.acknowledge!
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# # Start background threads that will call the block passed to listen.
|
41
|
+
# subscriber.start
|
42
|
+
#
|
43
|
+
# # Shut down the subscriber when ready to stop receiving messages.
|
44
|
+
# subscriber.stop!
|
45
|
+
#
|
46
|
+
# @attr_reader [String] subscription_name The name of the subscription the
|
47
|
+
# messages are pulled from.
|
48
|
+
# @attr_reader [Proc] callback The procedure that will handle the messages
|
49
|
+
# received from the subscription.
|
50
|
+
# @attr_reader [Numeric] deadline The default number of seconds the stream
|
51
|
+
# will hold received messages before modifying the message's ack
|
52
|
+
# deadline. The minimum is 10, the maximum is 600. Default is 60.
|
53
|
+
# @attr_reader [Boolean] message_ordering Whether message ordering has
|
54
|
+
# been enabled.
|
55
|
+
# @attr_reader [Integer] streams The number of concurrent streams to open
|
56
|
+
# to pull messages from the subscription. Default is 4.
|
57
|
+
# @attr_reader [Integer] callback_threads The number of threads used to
|
58
|
+
# handle the received messages. Default is 8.
|
59
|
+
# @attr_reader [Integer] push_threads The number of threads to handle
|
60
|
+
# acknowledgement ({ReceivedMessage#ack!}) and delay messages
|
61
|
+
# ({ReceivedMessage#nack!}, {ReceivedMessage#modify_ack_deadline!}).
|
62
|
+
# Default is 4.
|
63
|
+
#
|
64
|
+
class Subscriber
|
65
|
+
include MonitorMixin
|
66
|
+
|
67
|
+
attr_reader :subscription_name
|
68
|
+
attr_reader :callback
|
69
|
+
attr_reader :deadline
|
70
|
+
attr_reader :streams
|
71
|
+
attr_reader :message_ordering
|
72
|
+
attr_reader :callback_threads
|
73
|
+
attr_reader :push_threads
|
74
|
+
|
75
|
+
##
|
76
|
+
# @private Implementation attributes.
|
77
|
+
attr_reader :stream_pool, :thread_pool, :buffer, :service
|
78
|
+
|
79
|
+
##
|
80
|
+
# @private Create an empty {Subscriber} object.
|
81
|
+
def initialize subscription_name, callback, deadline: nil, message_ordering: nil, streams: nil, inventory: nil,
|
82
|
+
threads: {}, service: nil
|
83
|
+
super() # to init MonitorMixin
|
84
|
+
|
85
|
+
@callback = callback
|
86
|
+
@error_callbacks = []
|
87
|
+
@subscription_name = subscription_name
|
88
|
+
@deadline = deadline || 60
|
89
|
+
@streams = streams || 2
|
90
|
+
coerce_inventory inventory
|
91
|
+
@message_ordering = message_ordering
|
92
|
+
@callback_threads = Integer(threads[:callback] || 8)
|
93
|
+
@push_threads = Integer(threads[:push] || 4)
|
94
|
+
|
95
|
+
@service = service
|
96
|
+
|
97
|
+
@started = @stopped = nil
|
98
|
+
|
99
|
+
stream_pool = Array.new @streams do
|
100
|
+
Thread.new { Stream.new self }
|
101
|
+
end
|
102
|
+
@stream_pool = stream_pool.map(&:value)
|
103
|
+
|
104
|
+
@buffer = TimedUnaryBuffer.new self
|
105
|
+
end
|
106
|
+
|
107
|
+
##
|
108
|
+
# Starts the subscriber pulling from the subscription and processing the
|
109
|
+
# received messages.
|
110
|
+
#
|
111
|
+
# @return [Subscriber] returns self so calls can be chained.
|
112
|
+
#
|
113
|
+
def start
|
114
|
+
start_pool = synchronize do
|
115
|
+
@started = true
|
116
|
+
@stopped = false
|
117
|
+
|
118
|
+
# Start the buffer before the streams are all started
|
119
|
+
@buffer.start
|
120
|
+
@stream_pool.map do |stream|
|
121
|
+
Thread.new { stream.start }
|
122
|
+
end
|
123
|
+
end
|
124
|
+
start_pool.map(&:join)
|
125
|
+
|
126
|
+
self
|
127
|
+
end
|
128
|
+
|
129
|
+
##
|
130
|
+
# Immediately stops the subscriber. No new messages will be pulled from
|
131
|
+
# the subscription. Use {#wait!} to block until all received messages have
|
132
|
+
# been processed or released: All actions taken on received messages that
|
133
|
+
# have not yet been sent to the API will be sent to the API. All received
|
134
|
+
# but unprocessed messages will be released back to the API and redelivered.
|
135
|
+
#
|
136
|
+
# @return [Subscriber] returns self so calls can be chained.
|
137
|
+
#
|
138
|
+
def stop
|
139
|
+
synchronize do
|
140
|
+
@started = false
|
141
|
+
@stopped = true
|
142
|
+
@stream_pool.map(&:stop)
|
143
|
+
wait_stop_buffer_thread!
|
144
|
+
self
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
##
|
149
|
+
# Blocks until the subscriber is fully stopped and all received messages
|
150
|
+
# have been processed or released, or until `timeout` seconds have
|
151
|
+
# passed.
|
152
|
+
#
|
153
|
+
# Does not stop the subscriber. To stop the subscriber, first call
|
154
|
+
# {#stop} and then call {#wait!} to block until the subscriber is
|
155
|
+
# stopped.
|
156
|
+
#
|
157
|
+
# @param [Number, nil] timeout The number of seconds to block until the
|
158
|
+
# subscriber is fully stopped. Default will block indefinitely.
|
159
|
+
#
|
160
|
+
# @return [Subscriber] returns self so calls can be chained.
|
161
|
+
#
|
162
|
+
def wait! timeout = nil
|
163
|
+
wait_stop_buffer_thread!
|
164
|
+
@wait_stop_buffer_thread.join timeout
|
165
|
+
self
|
166
|
+
end
|
167
|
+
|
168
|
+
##
|
169
|
+
# Stop this subscriber and block until the subscriber is fully stopped
|
170
|
+
# and all received messages have been processed or released, or until
|
171
|
+
# `timeout` seconds have passed.
|
172
|
+
#
|
173
|
+
# The same as calling {#stop} and {#wait!}.
|
174
|
+
#
|
175
|
+
# @param [Number, nil] timeout The number of seconds to block until the
|
176
|
+
# subscriber is fully stopped. Default will block indefinitely.
|
177
|
+
#
|
178
|
+
# @return [Subscriber] returns self so calls can be chained.
|
179
|
+
#
|
180
|
+
def stop! timeout = nil
|
181
|
+
stop
|
182
|
+
wait! timeout
|
183
|
+
end
|
184
|
+
|
185
|
+
##
|
186
|
+
# Whether the subscriber has been started.
|
187
|
+
#
|
188
|
+
# @return [boolean] `true` when started, `false` otherwise.
|
189
|
+
#
|
190
|
+
def started?
|
191
|
+
synchronize { @started }
|
192
|
+
end
|
193
|
+
|
194
|
+
##
|
195
|
+
# Whether the subscriber has been stopped.
|
196
|
+
#
|
197
|
+
# @return [boolean] `true` when stopped, `false` otherwise.
|
198
|
+
#
|
199
|
+
def stopped?
|
200
|
+
synchronize { @stopped }
|
201
|
+
end
|
202
|
+
|
203
|
+
##
|
204
|
+
# Register to be notified of errors when raised.
|
205
|
+
#
|
206
|
+
# If an unhandled error has occurred the subscriber will attempt to
|
207
|
+
# recover from the error and resume listening.
|
208
|
+
#
|
209
|
+
# Multiple error handlers can be added.
|
210
|
+
#
|
211
|
+
# @yield [callback] The block to be called when an error is raised.
|
212
|
+
# @yieldparam [Exception] error The error raised.
|
213
|
+
#
|
214
|
+
# @example
|
215
|
+
# require "google/cloud/pubsub"
|
216
|
+
#
|
217
|
+
# pubsub = Google::Cloud::PubSub.new
|
218
|
+
#
|
219
|
+
# sub = pubsub.subscription "my-topic-sub"
|
220
|
+
#
|
221
|
+
# subscriber = sub.listen do |received_message|
|
222
|
+
# # process message
|
223
|
+
# received_message.acknowledge!
|
224
|
+
# end
|
225
|
+
#
|
226
|
+
# # Register to be notified when unhandled errors occur.
|
227
|
+
# subscriber.on_error do |error|
|
228
|
+
# # log error
|
229
|
+
# puts error
|
230
|
+
# end
|
231
|
+
#
|
232
|
+
# # Start listening for messages and errors.
|
233
|
+
# subscriber.start
|
234
|
+
#
|
235
|
+
# # Shut down the subscriber when ready to stop receiving messages.
|
236
|
+
# subscriber.stop!
|
237
|
+
#
|
238
|
+
def on_error &block
|
239
|
+
synchronize do
|
240
|
+
@error_callbacks << block
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
##
|
245
|
+
# The most recent unhandled error to occur while listening to messages
|
246
|
+
# on the subscriber.
|
247
|
+
#
|
248
|
+
# If an unhandled error has occurred the subscriber will attempt to
|
249
|
+
# recover from the error and resume listening.
|
250
|
+
#
|
251
|
+
# @return [Exception, nil] error The most recent error raised.
|
252
|
+
#
|
253
|
+
# @example
|
254
|
+
# require "google/cloud/pubsub"
|
255
|
+
#
|
256
|
+
# pubsub = Google::Cloud::PubSub.new
|
257
|
+
#
|
258
|
+
# sub = pubsub.subscription "my-topic-sub"
|
259
|
+
#
|
260
|
+
# subscriber = sub.listen do |received_message|
|
261
|
+
# # process message
|
262
|
+
# received_message.acknowledge!
|
263
|
+
# end
|
264
|
+
#
|
265
|
+
# # Start listening for messages and errors.
|
266
|
+
# subscriber.start
|
267
|
+
#
|
268
|
+
# # If an error was raised, it can be retrieved here:
|
269
|
+
# subscriber.last_error #=> nil
|
270
|
+
#
|
271
|
+
# # Shut down the subscriber when ready to stop receiving messages.
|
272
|
+
# subscriber.stop!
|
273
|
+
#
|
274
|
+
def last_error
|
275
|
+
synchronize { @last_error }
|
276
|
+
end
|
277
|
+
|
278
|
+
##
|
279
|
+
# The number of received messages to be collected by subscriber. Default is 1,000.
|
280
|
+
#
|
281
|
+
# @return [Integer] The maximum number of messages.
|
282
|
+
#
|
283
|
+
def max_outstanding_messages
|
284
|
+
@inventory[:max_outstanding_messages]
|
285
|
+
end
|
286
|
+
# @deprecated Use {#max_outstanding_messages}.
|
287
|
+
alias inventory_limit max_outstanding_messages
|
288
|
+
# @deprecated Use {#max_outstanding_messages}.
|
289
|
+
alias inventory max_outstanding_messages
|
290
|
+
|
291
|
+
##
|
292
|
+
# The total byte size of received messages to be collected by subscriber. Default is 100,000,000 (100MB).
|
293
|
+
#
|
294
|
+
# @return [Integer] The maximum number of bytes.
|
295
|
+
#
|
296
|
+
def max_outstanding_bytes
|
297
|
+
@inventory[:max_outstanding_bytes]
|
298
|
+
end
|
299
|
+
# @deprecated Use {#max_outstanding_bytes}.
|
300
|
+
alias inventory_bytesize max_outstanding_bytes
|
301
|
+
|
302
|
+
##
|
303
|
+
# Whether to enforce flow control at the client side only or to enforce it at both the client and
|
304
|
+
# the server. For more details about flow control see https://cloud.google.com/pubsub/docs/pull#config.
|
305
|
+
#
|
306
|
+
# @return [Boolean] `true` when only client side flow control is enforced, `false` when both client and
|
307
|
+
# server side flow control are enforced.
|
308
|
+
#
|
309
|
+
def use_legacy_flow_control?
|
310
|
+
@inventory[:use_legacy_flow_control]
|
311
|
+
end
|
312
|
+
|
313
|
+
##
|
314
|
+
# The number of seconds that received messages can be held awaiting processing. Default is 3,600 (1 hour).
|
315
|
+
#
|
316
|
+
# @return [Integer] The maximum number of seconds.
|
317
|
+
#
|
318
|
+
def max_total_lease_duration
|
319
|
+
@inventory[:max_total_lease_duration]
|
320
|
+
end
|
321
|
+
# @deprecated Use {#max_total_lease_duration}.
|
322
|
+
alias inventory_extension max_total_lease_duration
|
323
|
+
|
324
|
+
##
|
325
|
+
# The maximum amount of time in seconds for a single lease extension attempt. Bounds the delay before a message
|
326
|
+
# redelivery if the subscriber fails to extend the deadline. Default is 0 (disabled).
|
327
|
+
#
|
328
|
+
# @return [Integer] The maximum number of seconds.
|
329
|
+
#
|
330
|
+
def max_duration_per_lease_extension
|
331
|
+
@inventory[:max_duration_per_lease_extension]
|
332
|
+
end
|
333
|
+
|
334
|
+
##
|
335
|
+
# @private
|
336
|
+
def stream_inventory
|
337
|
+
{
|
338
|
+
limit: @inventory[:max_outstanding_messages].fdiv(@streams).ceil,
|
339
|
+
bytesize: @inventory[:max_outstanding_bytes].fdiv(@streams).ceil,
|
340
|
+
extension: @inventory[:max_total_lease_duration],
|
341
|
+
max_duration_per_lease_extension: @inventory[:max_duration_per_lease_extension],
|
342
|
+
use_legacy_flow_control: @inventory[:use_legacy_flow_control]
|
343
|
+
}
|
344
|
+
end
|
345
|
+
|
346
|
+
# @private returns error object from the stream thread.
|
347
|
+
def error! error
|
348
|
+
error_callbacks = synchronize do
|
349
|
+
@last_error = error
|
350
|
+
@error_callbacks
|
351
|
+
end
|
352
|
+
error_callbacks = default_error_callbacks if error_callbacks.empty?
|
353
|
+
error_callbacks.each { |error_callback| error_callback.call error }
|
354
|
+
end
|
355
|
+
|
356
|
+
##
|
357
|
+
# @private
|
358
|
+
def to_s
|
359
|
+
"(subscription: #{subscription_name}, streams: [#{stream_pool.map(&:to_s).join(', ')}])"
|
360
|
+
end
|
361
|
+
|
362
|
+
##
|
363
|
+
# @private
|
364
|
+
def inspect
|
365
|
+
"#<#{self.class.name} #{self}>"
|
366
|
+
end
|
367
|
+
|
368
|
+
protected
|
369
|
+
|
370
|
+
##
|
371
|
+
# Starts a new thread to call wait! (blocking) on each Stream and then stop the TimedUnaryBuffer.
|
372
|
+
def wait_stop_buffer_thread!
|
373
|
+
synchronize do
|
374
|
+
@wait_stop_buffer_thread ||= Thread.new do
|
375
|
+
@stream_pool.map(&:wait!)
|
376
|
+
# Shutdown the buffer TimerTask (and flush the buffer) after the streams are all stopped.
|
377
|
+
@buffer.stop
|
378
|
+
end
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
def coerce_inventory inventory
|
383
|
+
@inventory = inventory
|
384
|
+
if @inventory.is_a? Hash
|
385
|
+
@inventory = @inventory.dup
|
386
|
+
# Support deprecated field names
|
387
|
+
@inventory[:max_outstanding_messages] ||= @inventory.delete :limit
|
388
|
+
@inventory[:max_outstanding_bytes] ||= @inventory.delete :bytesize
|
389
|
+
@inventory[:max_total_lease_duration] ||= @inventory.delete :extension
|
390
|
+
else
|
391
|
+
@inventory = { max_outstanding_messages: @inventory }
|
392
|
+
end
|
393
|
+
@inventory[:max_outstanding_messages] = Integer(@inventory[:max_outstanding_messages] || 1000)
|
394
|
+
@inventory[:max_outstanding_bytes] = Integer(@inventory[:max_outstanding_bytes] || 100_000_000)
|
395
|
+
@inventory[:max_total_lease_duration] = Integer(@inventory[:max_total_lease_duration] || 3600)
|
396
|
+
@inventory[:max_duration_per_lease_extension] = Integer(@inventory[:max_duration_per_lease_extension] || 0)
|
397
|
+
@inventory[:use_legacy_flow_control] = @inventory[:use_legacy_flow_control] || false
|
398
|
+
end
|
399
|
+
|
400
|
+
def default_error_callbacks
|
401
|
+
# This is memoized to reduce calls to the configuration.
|
402
|
+
@default_error_callbacks ||= begin
|
403
|
+
error_callback = Google::Cloud::PubSub.configure.on_error
|
404
|
+
error_callback ||= Google::Cloud.configure.on_error
|
405
|
+
if error_callback
|
406
|
+
[error_callback]
|
407
|
+
else
|
408
|
+
[]
|
409
|
+
end
|
410
|
+
end
|
411
|
+
end
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
Pubsub = PubSub unless const_defined? :Pubsub
|
416
|
+
end
|
417
|
+
end
|