google-cloud-pubsub 0.31.1 → 0.32.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +1 -0
- data/README.md +8 -8
- data/lib/google/cloud/pubsub/async_publisher.rb +4 -0
- data/lib/google/cloud/pubsub/credentials.rb +2 -14
- data/lib/google/cloud/pubsub/subscriber.rb +85 -0
- data/lib/google/cloud/pubsub/subscriber/async_stream_pusher.rb +24 -19
- data/lib/google/cloud/pubsub/subscriber/async_unary_pusher.rb +45 -26
- data/lib/google/cloud/pubsub/subscriber/inventory.rb +136 -0
- data/lib/google/cloud/pubsub/subscriber/stream.rb +80 -138
- data/lib/google/cloud/pubsub/subscription.rb +2 -2
- data/lib/google/cloud/pubsub/topic.rb +4 -4
- data/lib/google/cloud/pubsub/v1/credentials.rb +38 -0
- data/lib/google/cloud/pubsub/v1/doc/google/iam/v1/iam_policy.rb +62 -0
- data/lib/google/cloud/pubsub/v1/doc/google/iam/v1/policy.rb +127 -0
- data/lib/google/cloud/pubsub/v1/doc/google/protobuf/duration.rb +1 -1
- data/lib/google/cloud/pubsub/v1/doc/google/protobuf/empty.rb +28 -0
- data/lib/google/cloud/pubsub/v1/doc/google/protobuf/field_mask.rb +1 -1
- data/lib/google/cloud/pubsub/v1/doc/google/protobuf/timestamp.rb +1 -1
- data/lib/google/cloud/pubsub/v1/doc/google/pubsub/v1/pubsub.rb +113 -31
- data/lib/google/cloud/pubsub/v1/publisher_client.rb +180 -109
- data/lib/google/cloud/pubsub/v1/subscriber_client.rb +322 -193
- data/lib/google/cloud/pubsub/v1/subscriber_client_config.json +1 -1
- data/lib/google/cloud/pubsub/version.rb +1 -1
- data/lib/google/pubsub/v1/pubsub_pb.rb +21 -0
- data/lib/google/pubsub/v1/pubsub_services_pb.rb +87 -73
- metadata +23 -5
- data/lib/google/cloud/pubsub/v1/doc/overview.rb +0 -75
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 47a9873e0c2c11d5625c00418517bf241b344dd45edf5efabace63b042e26137
|
4
|
+
data.tar.gz: 6cd96cfb644807699b787fa4502905923ca522f2ae5efefe937d8b08b04eeeeb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1bd5df7f2e73e44bcd51c60f00baf3097567c9703899b6bffe5d0384a59b30f9fb33ed48b396674d221872c39831697168f5a541604ec48a0e08d08ea20d7f4a
|
7
|
+
data.tar.gz: 1cba0d5355c7565ab5c6b3787c72d55a27b31ff5555a5e9995641f8d88e291c88476c473621d090f1618cff7023604ac5616fa5106b34cca0d49f507a6b63111
|
data/.yardopts
CHANGED
data/README.md
CHANGED
@@ -74,14 +74,14 @@ end
|
|
74
74
|
|
75
75
|
## Supported Ruby Versions
|
76
76
|
|
77
|
-
This library is supported on Ruby 2.
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
77
|
+
This library is supported on Ruby 2.3+.
|
78
|
+
|
79
|
+
Google provides official support for Ruby versions that are actively supported
|
80
|
+
by Ruby Core—that is, Ruby versions that are either in normal maintenance or
|
81
|
+
in security maintenance, and not end of life. Currently, this means Ruby 2.3
|
82
|
+
and later. Older versions of Ruby _may_ still work, but are unsupported and not
|
83
|
+
recommended. See https://www.ruby-lang.org/en/downloads/branches/ for details
|
84
|
+
about the Ruby support schedule.
|
85
85
|
|
86
86
|
## Versioning
|
87
87
|
|
@@ -228,6 +228,8 @@ module Google
|
|
228
228
|
end
|
229
229
|
|
230
230
|
def publish_batch_async topic_name, batch
|
231
|
+
return unless @publish_thread_pool.running?
|
232
|
+
|
231
233
|
Concurrent::Future.new(executor: @publish_thread_pool) do
|
232
234
|
begin
|
233
235
|
grpc = @service.publish topic_name, batch.messages
|
@@ -250,6 +252,8 @@ module Google
|
|
250
252
|
end
|
251
253
|
|
252
254
|
def execute_callback_async callback, publish_result
|
255
|
+
return unless @callback_thread_pool.running?
|
256
|
+
|
253
257
|
Concurrent::Future.new(executor: @callback_thread_pool) do
|
254
258
|
callback.call publish_result
|
255
259
|
end.execute
|
@@ -14,6 +14,7 @@
|
|
14
14
|
|
15
15
|
|
16
16
|
require "googleauth"
|
17
|
+
require "google/cloud/pubsub/v1/credentials.rb"
|
17
18
|
|
18
19
|
module Google
|
19
20
|
module Cloud
|
@@ -37,20 +38,7 @@ module Google
|
|
37
38
|
#
|
38
39
|
# pubsub.project_id #=> "my-project"
|
39
40
|
#
|
40
|
-
class Credentials < Google::
|
41
|
-
SCOPE = ["https://www.googleapis.com/auth/pubsub"].freeze
|
42
|
-
PATH_ENV_VARS = %w[PUBSUB_CREDENTIALS
|
43
|
-
PUBSUB_KEYFILE
|
44
|
-
GOOGLE_CLOUD_CREDENTIALS
|
45
|
-
GOOGLE_CLOUD_KEYFILE
|
46
|
-
GCLOUD_KEYFILE].freeze
|
47
|
-
JSON_ENV_VARS = %w[PUBSUB_CREDENTIALS_JSON
|
48
|
-
PUBSUB_KEYFILE_JSON
|
49
|
-
GOOGLE_CLOUD_CREDENTIALS_JSON
|
50
|
-
GOOGLE_CLOUD_KEYFILE_JSON
|
51
|
-
GCLOUD_KEYFILE_JSON].freeze
|
52
|
-
DEFAULT_PATHS = \
|
53
|
-
["~/.config/gcloud/application_default_credentials.json"].freeze
|
41
|
+
class Credentials < Google::Cloud::Pubsub::V1::Credentials
|
54
42
|
end
|
55
43
|
end
|
56
44
|
end
|
@@ -74,6 +74,7 @@ module Google
|
|
74
74
|
def initialize subscription_name, callback, deadline: nil, streams: nil,
|
75
75
|
inventory: nil, threads: {}, service: nil
|
76
76
|
@callback = callback
|
77
|
+
@error_callbacks = []
|
77
78
|
@subscription_name = subscription_name
|
78
79
|
@deadline = deadline || 60
|
79
80
|
@streams = streams || 4
|
@@ -169,6 +170,90 @@ module Google
|
|
169
170
|
synchronize { @stopped }
|
170
171
|
end
|
171
172
|
|
173
|
+
##
|
174
|
+
# Register to be notified of errors when raised.
|
175
|
+
#
|
176
|
+
# If an unhandled error has occurred the subscriber will attempt to
|
177
|
+
# recover from the error and resume listening.
|
178
|
+
#
|
179
|
+
# Multiple error handlers can be added.
|
180
|
+
#
|
181
|
+
# @yield [callback] The block to be called when an error is raised.
|
182
|
+
# @yieldparam [Exception] error The error raised.
|
183
|
+
#
|
184
|
+
# @example
|
185
|
+
# require "google/cloud/pubsub"
|
186
|
+
#
|
187
|
+
# pubsub = Google::Cloud::Pubsub.new
|
188
|
+
#
|
189
|
+
# sub = pubsub.subscription "my-topic-sub"
|
190
|
+
#
|
191
|
+
# subscriber = sub.listen do |received_message|
|
192
|
+
# # process message
|
193
|
+
# received_message.acknowledge!
|
194
|
+
# end
|
195
|
+
#
|
196
|
+
# # Register to be notified when unhandled errors occur.
|
197
|
+
# subscriber.on_error do |error|
|
198
|
+
# # log error
|
199
|
+
# puts error
|
200
|
+
# end
|
201
|
+
#
|
202
|
+
# # Start listening for messages and errors.
|
203
|
+
# subscriber.start
|
204
|
+
#
|
205
|
+
# # Shut down the subscriber when ready to stop receiving messages.
|
206
|
+
# subscriber.stop.wait!
|
207
|
+
#
|
208
|
+
def on_error &block
|
209
|
+
synchronize do
|
210
|
+
@error_callbacks << block
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
##
|
215
|
+
# The most recent unhandled error to occur while listening to messages
|
216
|
+
# on the subscriber.
|
217
|
+
#
|
218
|
+
# If an unhandled error has occurred the subscriber will attempt to
|
219
|
+
# recover from the error and resume listening.
|
220
|
+
#
|
221
|
+
# @return [Exception, nil] error The most recent error raised.
|
222
|
+
#
|
223
|
+
# @example
|
224
|
+
# require "google/cloud/pubsub"
|
225
|
+
#
|
226
|
+
# pubsub = Google::Cloud::Pubsub.new
|
227
|
+
#
|
228
|
+
# sub = pubsub.subscription "my-topic-sub"
|
229
|
+
#
|
230
|
+
# subscriber = sub.listen do |received_message|
|
231
|
+
# # process message
|
232
|
+
# received_message.acknowledge!
|
233
|
+
# end
|
234
|
+
#
|
235
|
+
# # Start listening for messages and errors.
|
236
|
+
# subscriber.start
|
237
|
+
#
|
238
|
+
# # If an error was raised, it can be retrieved here:
|
239
|
+
# subscriber.last_error #=> nil
|
240
|
+
#
|
241
|
+
# # Shut down the subscriber when ready to stop receiving messages.
|
242
|
+
# subscriber.stop.wait!
|
243
|
+
#
|
244
|
+
def last_error
|
245
|
+
synchronize { @last_error }
|
246
|
+
end
|
247
|
+
|
248
|
+
# @private returns error object from the stream thread.
|
249
|
+
def error! error
|
250
|
+
error_callbacks = synchronize do
|
251
|
+
@last_error = error
|
252
|
+
@error_callbacks
|
253
|
+
end
|
254
|
+
error_callbacks.each { |error_callback| error_callback.call error }
|
255
|
+
end
|
256
|
+
|
172
257
|
##
|
173
258
|
# @private
|
174
259
|
def to_s
|
@@ -59,9 +59,6 @@ module Google
|
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
-
@batch_created_at ||= Time.now
|
63
|
-
@background_thread ||= Thread.new { run_background }
|
64
|
-
|
65
62
|
push_batch_request! if @batch.ready?
|
66
63
|
end
|
67
64
|
|
@@ -88,9 +85,6 @@ module Google
|
|
88
85
|
end
|
89
86
|
end
|
90
87
|
|
91
|
-
@batch_created_at ||= Time.now
|
92
|
-
@background_thread ||= Thread.new { run_background }
|
93
|
-
|
94
88
|
push_batch_request! if @batch.ready?
|
95
89
|
end
|
96
90
|
|
@@ -100,15 +94,25 @@ module Google
|
|
100
94
|
nil
|
101
95
|
end
|
102
96
|
|
97
|
+
def start
|
98
|
+
synchronize do
|
99
|
+
@stopped = false
|
100
|
+
|
101
|
+
@background_thread ||= Thread.new { run_background }
|
102
|
+
end
|
103
|
+
|
104
|
+
self
|
105
|
+
end
|
106
|
+
|
103
107
|
def stop
|
104
108
|
synchronize do
|
105
|
-
|
109
|
+
push_batch_request!
|
106
110
|
|
107
|
-
|
108
|
-
@
|
111
|
+
@stopped = true
|
112
|
+
@cond.broadcast
|
109
113
|
end
|
110
114
|
|
111
|
-
|
115
|
+
self
|
112
116
|
end
|
113
117
|
|
114
118
|
def started?
|
@@ -125,19 +129,20 @@ module Google
|
|
125
129
|
synchronize do
|
126
130
|
until @stopped
|
127
131
|
if @batch.nil?
|
128
|
-
@cond.wait
|
132
|
+
@cond.wait # wait until broadcast
|
129
133
|
next
|
130
134
|
end
|
131
135
|
|
132
|
-
|
133
|
-
|
136
|
+
time_from_batch_creation = Time.now - @batch.created_at
|
137
|
+
time_until_next_push = @interval - time_from_batch_creation
|
138
|
+
|
139
|
+
if time_until_next_push <= 0
|
134
140
|
# interval met, publish the batch...
|
135
141
|
push_batch_request!
|
136
|
-
|
137
|
-
else
|
138
|
-
# still waiting for the interval to publish the batch...
|
139
|
-
@cond.wait(@interval - time_since_batch_creation)
|
142
|
+
time_until_next_push = nil # wait until broadcast
|
140
143
|
end
|
144
|
+
|
145
|
+
@cond.wait time_until_next_push
|
141
146
|
end
|
142
147
|
end
|
143
148
|
end
|
@@ -148,16 +153,16 @@ module Google
|
|
148
153
|
@stream.push @batch.request
|
149
154
|
|
150
155
|
@batch = nil
|
151
|
-
@batch_created_at = nil
|
152
156
|
end
|
153
157
|
|
154
158
|
class Batch
|
155
|
-
attr_reader :max_bytes, :request
|
159
|
+
attr_reader :max_bytes, :request, :created_at
|
156
160
|
|
157
161
|
def initialize max_bytes: 10000000
|
158
162
|
@max_bytes = max_bytes
|
159
163
|
@request = Google::Pubsub::V1::StreamingPullRequest.new
|
160
164
|
@total_message_bytes = 0
|
165
|
+
@created_at = Time.now
|
161
166
|
end
|
162
167
|
|
163
168
|
def ack ack_id
|
@@ -59,9 +59,6 @@ module Google
|
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
-
@batch_created_at ||= Time.now
|
63
|
-
@background_thread ||= Thread.new { run_background }
|
64
|
-
|
65
62
|
push_batch_request! if @batch.ready?
|
66
63
|
end
|
67
64
|
|
@@ -88,9 +85,6 @@ module Google
|
|
88
85
|
end
|
89
86
|
end
|
90
87
|
|
91
|
-
@batch_created_at ||= Time.now
|
92
|
-
@background_thread ||= Thread.new { run_background }
|
93
|
-
|
94
88
|
push_batch_request! if @batch.ready?
|
95
89
|
end
|
96
90
|
|
@@ -100,15 +94,25 @@ module Google
|
|
100
94
|
nil
|
101
95
|
end
|
102
96
|
|
97
|
+
def start
|
98
|
+
synchronize do
|
99
|
+
@stopped = false
|
100
|
+
|
101
|
+
@background_thread ||= Thread.new { run_background }
|
102
|
+
end
|
103
|
+
|
104
|
+
self
|
105
|
+
end
|
106
|
+
|
103
107
|
def stop
|
104
108
|
synchronize do
|
105
|
-
|
109
|
+
push_batch_request!
|
106
110
|
|
107
|
-
|
108
|
-
@
|
111
|
+
@stopped = true
|
112
|
+
@cond.broadcast
|
109
113
|
end
|
110
114
|
|
111
|
-
|
115
|
+
self
|
112
116
|
end
|
113
117
|
|
114
118
|
def started?
|
@@ -125,19 +129,20 @@ module Google
|
|
125
129
|
synchronize do
|
126
130
|
until @stopped
|
127
131
|
if @batch.nil?
|
128
|
-
@cond.wait
|
132
|
+
@cond.wait # wait until broadcast
|
129
133
|
next
|
130
134
|
end
|
131
135
|
|
132
|
-
|
133
|
-
|
136
|
+
time_from_batch_creation = Time.now - @batch.created_at
|
137
|
+
time_until_next_push = @interval - time_from_batch_creation
|
138
|
+
|
139
|
+
if time_until_next_push <= 0
|
134
140
|
# interval met, publish the batch...
|
135
141
|
push_batch_request!
|
136
|
-
|
137
|
-
else
|
138
|
-
# still waiting for the interval to publish the batch...
|
139
|
-
@cond.wait(@interval - time_since_batch_creation)
|
142
|
+
time_until_next_push = nil # wait until broadcast
|
140
143
|
end
|
144
|
+
|
145
|
+
@cond.wait time_until_next_push
|
141
146
|
end
|
142
147
|
end
|
143
148
|
end
|
@@ -145,34 +150,48 @@ module Google
|
|
145
150
|
def push_batch_request!
|
146
151
|
return unless @batch
|
147
152
|
|
153
|
+
sub_name = @stream.subscriber.subscription_name
|
148
154
|
service = @stream.subscriber.service
|
149
|
-
name = @stream.subscriber.subscription_name
|
150
155
|
|
151
156
|
if @batch.ack?
|
152
157
|
ack_ids = @batch.ack_ids
|
153
|
-
|
154
|
-
service.acknowledge
|
155
|
-
end
|
158
|
+
push_change_request do
|
159
|
+
service.acknowledge sub_name, *ack_ids
|
160
|
+
end
|
156
161
|
end
|
157
162
|
if @batch.delay?
|
158
163
|
@batch.modify_deadline_hash.each do |delay_seconds, delay_ack_ids|
|
159
|
-
|
160
|
-
service.modify_ack_deadline
|
161
|
-
|
164
|
+
push_change_request do
|
165
|
+
service.modify_ack_deadline sub_name,
|
166
|
+
delay_ack_ids,
|
167
|
+
delay_seconds
|
168
|
+
end
|
162
169
|
end
|
163
170
|
end
|
164
171
|
|
165
172
|
@batch = nil
|
166
|
-
|
173
|
+
end
|
174
|
+
|
175
|
+
def push_change_request
|
176
|
+
return unless @stream.push_thread_pool.running?
|
177
|
+
|
178
|
+
Concurrent::Future.new(executor: @stream.push_thread_pool) do
|
179
|
+
begin
|
180
|
+
yield
|
181
|
+
rescue StandardError => push_error
|
182
|
+
@stream.subscriber.error! push_error
|
183
|
+
end
|
184
|
+
end.execute
|
167
185
|
end
|
168
186
|
|
169
187
|
class Batch
|
170
|
-
attr_reader :max_bytes, :request
|
188
|
+
attr_reader :max_bytes, :request, :created_at
|
171
189
|
|
172
190
|
def initialize max_bytes: 10000000
|
173
191
|
@max_bytes = max_bytes
|
174
192
|
@request = Google::Pubsub::V1::StreamingPullRequest.new
|
175
193
|
@total_message_bytes = 0
|
194
|
+
@created_at = Time.now
|
176
195
|
end
|
177
196
|
|
178
197
|
def ack ack_id
|
@@ -0,0 +1,136 @@
|
|
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 "monitor"
|
17
|
+
|
18
|
+
module Google
|
19
|
+
module Cloud
|
20
|
+
module Pubsub
|
21
|
+
class Subscriber
|
22
|
+
##
|
23
|
+
# @private
|
24
|
+
class Inventory
|
25
|
+
include MonitorMixin
|
26
|
+
|
27
|
+
attr_reader :stream, :limit
|
28
|
+
|
29
|
+
def initialize stream, limit
|
30
|
+
@stream = stream
|
31
|
+
@limit = limit
|
32
|
+
@_ack_ids = []
|
33
|
+
@wait_cond = new_cond
|
34
|
+
|
35
|
+
super()
|
36
|
+
end
|
37
|
+
|
38
|
+
def ack_ids
|
39
|
+
@_ack_ids
|
40
|
+
end
|
41
|
+
|
42
|
+
def add *ack_ids
|
43
|
+
ack_ids.flatten!.compact!
|
44
|
+
return if ack_ids.empty?
|
45
|
+
|
46
|
+
synchronize do
|
47
|
+
@_ack_ids += ack_ids
|
48
|
+
@wait_cond.broadcast
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def remove *ack_ids
|
53
|
+
ack_ids.flatten!.compact!
|
54
|
+
return if ack_ids.empty?
|
55
|
+
|
56
|
+
synchronize do
|
57
|
+
@_ack_ids -= ack_ids
|
58
|
+
@wait_cond.broadcast
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def count
|
63
|
+
synchronize do
|
64
|
+
@_ack_ids.count
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def empty?
|
69
|
+
synchronize do
|
70
|
+
@_ack_ids.empty?
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def start
|
75
|
+
@background_thread ||= Thread.new { background_run }
|
76
|
+
|
77
|
+
self
|
78
|
+
end
|
79
|
+
|
80
|
+
def stop
|
81
|
+
synchronize do
|
82
|
+
@stopped = true
|
83
|
+
@wait_cond.broadcast
|
84
|
+
end
|
85
|
+
|
86
|
+
self
|
87
|
+
end
|
88
|
+
|
89
|
+
def stopped?
|
90
|
+
synchronize { @stopped }
|
91
|
+
end
|
92
|
+
|
93
|
+
def full?
|
94
|
+
count >= limit
|
95
|
+
end
|
96
|
+
|
97
|
+
protected
|
98
|
+
|
99
|
+
def background_run
|
100
|
+
delay_target = nil
|
101
|
+
|
102
|
+
synchronize do
|
103
|
+
until @stopped
|
104
|
+
if @_ack_ids.empty?
|
105
|
+
delay_target = nil
|
106
|
+
|
107
|
+
@wait_cond.wait # wait until broadcast
|
108
|
+
next
|
109
|
+
end
|
110
|
+
|
111
|
+
delay_target ||= calc_target
|
112
|
+
delay_gap = delay_target - Time.now
|
113
|
+
|
114
|
+
unless delay_gap.positive?
|
115
|
+
delay_target = nil
|
116
|
+
delay_gap = nil # wait until broadcast
|
117
|
+
stream.delay_inventory!
|
118
|
+
end
|
119
|
+
|
120
|
+
@wait_cond.wait delay_gap
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def calc_target
|
126
|
+
Time.now + calc_delay
|
127
|
+
end
|
128
|
+
|
129
|
+
def calc_delay
|
130
|
+
(stream.subscriber.deadline - 3) * rand(0.8..0.9)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|