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.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -0
  3. data/README.md +8 -8
  4. data/lib/google/cloud/pubsub/async_publisher.rb +4 -0
  5. data/lib/google/cloud/pubsub/credentials.rb +2 -14
  6. data/lib/google/cloud/pubsub/subscriber.rb +85 -0
  7. data/lib/google/cloud/pubsub/subscriber/async_stream_pusher.rb +24 -19
  8. data/lib/google/cloud/pubsub/subscriber/async_unary_pusher.rb +45 -26
  9. data/lib/google/cloud/pubsub/subscriber/inventory.rb +136 -0
  10. data/lib/google/cloud/pubsub/subscriber/stream.rb +80 -138
  11. data/lib/google/cloud/pubsub/subscription.rb +2 -2
  12. data/lib/google/cloud/pubsub/topic.rb +4 -4
  13. data/lib/google/cloud/pubsub/v1/credentials.rb +38 -0
  14. data/lib/google/cloud/pubsub/v1/doc/google/iam/v1/iam_policy.rb +62 -0
  15. data/lib/google/cloud/pubsub/v1/doc/google/iam/v1/policy.rb +127 -0
  16. data/lib/google/cloud/pubsub/v1/doc/google/protobuf/duration.rb +1 -1
  17. data/lib/google/cloud/pubsub/v1/doc/google/protobuf/empty.rb +28 -0
  18. data/lib/google/cloud/pubsub/v1/doc/google/protobuf/field_mask.rb +1 -1
  19. data/lib/google/cloud/pubsub/v1/doc/google/protobuf/timestamp.rb +1 -1
  20. data/lib/google/cloud/pubsub/v1/doc/google/pubsub/v1/pubsub.rb +113 -31
  21. data/lib/google/cloud/pubsub/v1/publisher_client.rb +180 -109
  22. data/lib/google/cloud/pubsub/v1/subscriber_client.rb +322 -193
  23. data/lib/google/cloud/pubsub/v1/subscriber_client_config.json +1 -1
  24. data/lib/google/cloud/pubsub/version.rb +1 -1
  25. data/lib/google/pubsub/v1/pubsub_pb.rb +21 -0
  26. data/lib/google/pubsub/v1/pubsub_services_pb.rb +87 -73
  27. metadata +23 -5
  28. 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: 3817e592071ccc0badbc1c511c848341de65d0e5fb4b9feba8c528074cd71724
4
- data.tar.gz: 9e789ffcc98b3672040ff67f5e198f6f214cde83a205d6893982ca87b5e99e2b
3
+ metadata.gz: 47a9873e0c2c11d5625c00418517bf241b344dd45edf5efabace63b042e26137
4
+ data.tar.gz: 6cd96cfb644807699b787fa4502905923ca522f2ae5efefe937d8b08b04eeeeb
5
5
  SHA512:
6
- metadata.gz: 52e115e0f6bf8968976a853064e30088374ea1836410785e3042fe00324f065e085d54e7b1502a34cd8fde8dc4395b901a95293856846f8b5b6f0af421c11586
7
- data.tar.gz: 2cf2bf6b75e926fcb0fda9ba22cae4a49a75b0fc7d408faf61ecc90fbd5a424e496369780eadee1b3fa90a448b37052933d70ee6b790dbed81ecbaed18380bae
6
+ metadata.gz: 1bd5df7f2e73e44bcd51c60f00baf3097567c9703899b6bffe5d0384a59b30f9fb33ed48b396674d221872c39831697168f5a541604ec48a0e08d08ea20d7f4a
7
+ data.tar.gz: 1cba0d5355c7565ab5c6b3787c72d55a27b31ff5555a5e9995641f8d88e291c88476c473621d090f1618cff7023604ac5616fa5106b34cca0d49f507a6b63111
data/.yardopts CHANGED
@@ -2,6 +2,7 @@
2
2
  --title=Google Cloud Pub/Sub
3
3
  --exclude lib/google/pubsub/v1
4
4
  --markup markdown
5
+ --markup-provider redcarpet
5
6
 
6
7
  ./lib/**/*.rb
7
8
  -
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.0+.
78
-
79
- However, Ruby 2.3 or later is strongly recommended, as earlier releases have
80
- reached or are nearing end-of-life. After June 1, 2018, Google will provide
81
- official support only for Ruby versions that are considered current and
82
- supported by Ruby Core (that is, Ruby versions that are either in normal
83
- maintenance or in security maintenance).
84
- See https://www.ruby-lang.org/en/downloads/branches/ for further details.
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::Auth::Credentials
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
- @stopped = true
109
+ push_batch_request!
106
110
 
107
- # Stop any background activity, clean up happens in wait!
108
- @background_thread.kill if @background_thread
111
+ @stopped = true
112
+ @cond.broadcast
109
113
  end
110
114
 
111
- push_batch_request!
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
- time_since_batch_creation = Time.now - @batch_created_at
133
- if time_since_batch_creation > @interval
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
- @cond.wait
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
- @stopped = true
109
+ push_batch_request!
106
110
 
107
- # Stop any background activity, clean up happens in wait!
108
- @background_thread.kill if @background_thread
111
+ @stopped = true
112
+ @cond.broadcast
109
113
  end
110
114
 
111
- push_batch_request!
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
- time_since_batch_creation = Time.now - @batch_created_at
133
- if time_since_batch_creation > @interval
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
- @cond.wait
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
- Concurrent::Future.new(executor: @stream.push_thread_pool) do
154
- service.acknowledge name, *ack_ids
155
- end.execute
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
- Concurrent::Future.new(executor: @stream.push_thread_pool) do
160
- service.modify_ack_deadline name, delay_ack_ids, delay_seconds
161
- end.execute
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
- @batch_created_at = nil
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