google-cloud-pubsub 0.30.2 → 0.31.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8bc2cbfb8b149d600fbdf725934ccef18019853c3c371d34d964a47532640b33
4
- data.tar.gz: 836fae2f33841cd070137fab258d208b456018214a25335f6e7848b1c9e0270b
3
+ metadata.gz: 3817e592071ccc0badbc1c511c848341de65d0e5fb4b9feba8c528074cd71724
4
+ data.tar.gz: 9e789ffcc98b3672040ff67f5e198f6f214cde83a205d6893982ca87b5e99e2b
5
5
  SHA512:
6
- metadata.gz: 55cf18d0b63d2f68f28db33f85dd21ded29e960e3cd871278b9abfedfa86829b49e3ea6ba96a7ad1fad15f96da65a2d75fb3f9c2dcd59025f1aba753878a79ca
7
- data.tar.gz: ce9772ea6d63bc664739c58ee56c32f84c44f9662c6ba9800a9aacd1a7e09eea9757649ca3290f8db894a07a4401ec4fd9f9573d5c4c7230b8e91ac0141c5fb1
6
+ metadata.gz: 52e115e0f6bf8968976a853064e30088374ea1836410785e3042fe00324f065e085d54e7b1502a34cd8fde8dc4395b901a95293856846f8b5b6f0af421c11586
7
+ data.tar.gz: 2cf2bf6b75e926fcb0fda9ba22cae4a49a75b0fc7d408faf61ecc90fbd5a424e496369780eadee1b3fa90a448b37052933d70ee6b790dbed81ecbaed18380bae
data/README.md CHANGED
@@ -50,6 +50,28 @@ subscriber.start
50
50
  subscriber.stop.wait!
51
51
  ```
52
52
 
53
+ ## Enabling Logging
54
+
55
+ To enable logging for this library, set the logger for the underlying [gRPC](https://github.com/grpc/grpc/tree/master/src/ruby) library. The logger that you set may be a Ruby stdlib [`Logger`](https://ruby-doc.org/stdlib-2.5.0/libdoc/logger/rdoc/Logger.html) as shown below, or a [`Google::Cloud::Logging::Logger`](https://googlecloudplatform.github.io/google-cloud-ruby/#/docs/google-cloud-logging/latest/google/cloud/logging/logger) that will write logs to [Stackdriver Logging](https://cloud.google.com/logging/). See [grpc/logconfig.rb](https://github.com/grpc/grpc/blob/master/src/ruby/lib/grpc/logconfig.rb) and the gRPC [spec_helper.rb](https://github.com/grpc/grpc/blob/master/src/ruby/spec/spec_helper.rb) for additional information.
56
+
57
+ Configuring a Ruby stdlib logger:
58
+
59
+ ```ruby
60
+ require "logger"
61
+
62
+ module MyLogger
63
+ LOGGER = Logger.new $stderr, level: Logger::WARN
64
+ def logger
65
+ LOGGER
66
+ end
67
+ end
68
+
69
+ # Define a gRPC module-level logger method before grpc/logconfig.rb loads.
70
+ module GRPC
71
+ extend MyLogger
72
+ end
73
+ ```
74
+
53
75
  ## Supported Ruby Versions
54
76
 
55
77
  This library is supported on Ruby 2.0+.
@@ -51,6 +51,39 @@ module Google
51
51
  # To learn more about Pub/Sub, read the [Google Cloud Pub/Sub Overview
52
52
  # ](https://cloud.google.com/pubsub/overview).
53
53
  #
54
+ # ## Enabling Logging
55
+ #
56
+ # To enable logging for this library, set the logger for the underlying
57
+ # [gRPC](https://github.com/grpc/grpc/tree/master/src/ruby) library. The
58
+ # logger that you set may be a Ruby stdlib
59
+ # [`Logger`](https://ruby-doc.org/stdlib-2.5.0/libdoc/logger/rdoc/Logger.html)
60
+ # as shown below, or a
61
+ # [`Google::Cloud::Logging::Logger`](https://googlecloudplatform.github.io/google-cloud-ruby/#/docs/google-cloud-logging/latest/google/cloud/logging/logger)
62
+ # that will write logs to [Stackdriver
63
+ # Logging](https://cloud.google.com/logging/). See
64
+ # [grpc/logconfig.rb](https://github.com/grpc/grpc/blob/master/src/ruby/lib/grpc/logconfig.rb)
65
+ # and the gRPC
66
+ # [spec_helper.rb](https://github.com/grpc/grpc/blob/master/src/ruby/spec/spec_helper.rb)
67
+ # for additional information.
68
+ #
69
+ # Configuring a Ruby stdlib logger:
70
+ #
71
+ # ```ruby
72
+ # require "logger"
73
+ #
74
+ # module MyLogger
75
+ # LOGGER = Logger.new $stderr, level: Logger::WARN
76
+ # def logger
77
+ # LOGGER
78
+ # end
79
+ # end
80
+ #
81
+ # # Define a gRPC module-level logger method before grpc/logconfig.rb loads.
82
+ # module GRPC
83
+ # extend MyLogger
84
+ # end
85
+ # ```
86
+ #
54
87
  # ## Retrieving Topics
55
88
  #
56
89
  # A Topic is a named resource to which messages are sent by publishers.
@@ -267,7 +267,8 @@ module Google
267
267
  data = data.read
268
268
  end
269
269
  # Convert data to encoded byte array to match the protobuf defn
270
- data_bytes = String(data).dup.force_encoding("ASCII-8BIT").freeze
270
+ data_bytes = \
271
+ String(data).dup.force_encoding(Encoding::ASCII_8BIT).freeze
271
272
 
272
273
  # Convert attributes to strings to match the protobuf definition
273
274
  attributes = Hash[attributes.map { |k, v| [String(k), String(v)] }]
@@ -84,7 +84,8 @@ module Google
84
84
  data = data.read
85
85
  end
86
86
  # Convert data to encoded byte array to match the protobuf defn
87
- data_bytes = String(data).dup.force_encoding("ASCII-8BIT").freeze
87
+ data_bytes = \
88
+ String(data).dup.force_encoding(Encoding::ASCII_8BIT).freeze
88
89
 
89
90
  # Convert attributes to strings to match the protobuf definition
90
91
  attributes = Hash[attributes.map { |k, v| [String(k), String(v)] }]
@@ -65,7 +65,7 @@ module Google
65
65
  attributes = Hash[attributes.map { |k, v| [String(k), String(v)] }]
66
66
 
67
67
  @grpc = Google::Pubsub::V1::PubsubMessage.new(
68
- data: String(data).encode("ASCII-8BIT"),
68
+ data: String(data).dup.force_encoding(Encoding::ASCII_8BIT),
69
69
  attributes: attributes
70
70
  )
71
71
  end
@@ -104,7 +104,7 @@ module Google
104
104
  # @private New Message from a Google::Pubsub::V1::PubsubMessage object.
105
105
  def self.from_grpc grpc
106
106
  new.tap do |m|
107
- m.instance_variable_set "@grpc", grpc
107
+ m.instance_variable_set :@grpc, grpc
108
108
  end
109
109
  end
110
110
  end
@@ -150,10 +150,10 @@ module Google
150
150
  Snapshot.from_grpc grpc, service
151
151
  end)
152
152
  token = grpc_list.next_page_token
153
- token = nil if token == ""
154
- subs.instance_variable_set "@token", token
155
- subs.instance_variable_set "@service", service
156
- subs.instance_variable_set "@max", max
153
+ token = nil if token == "".freeze
154
+ subs.instance_variable_set :@token, token
155
+ subs.instance_variable_set :@service, service
156
+ subs.instance_variable_set :@max, max
157
157
  subs
158
158
  end
159
159
 
@@ -22,9 +22,9 @@ module Google
22
22
  class Subscriber
23
23
  ##
24
24
  # @private
25
- # # AsyncPusher
25
+ # # AsyncStreamPusher
26
26
  #
27
- class AsyncPusher
27
+ class AsyncStreamPusher
28
28
  include MonitorMixin
29
29
 
30
30
  attr_reader :batch
@@ -108,9 +108,7 @@ module Google
108
108
  @background_thread.kill if @background_thread
109
109
  end
110
110
 
111
- return nil if @batch.nil?
112
-
113
- @batch.request
111
+ push_batch_request!
114
112
  end
115
113
 
116
114
  def started?
@@ -131,14 +129,14 @@ module Google
131
129
  next
132
130
  end
133
131
 
134
- time_since_first_publish = Time.now - @batch_created_at
135
- if time_since_first_publish > @interval
132
+ time_since_batch_creation = Time.now - @batch_created_at
133
+ if time_since_batch_creation > @interval
136
134
  # interval met, publish the batch...
137
135
  push_batch_request!
138
136
  @cond.wait
139
137
  else
140
138
  # still waiting for the interval to publish the batch...
141
- @cond.wait(@interval - time_since_first_publish)
139
+ @cond.wait(@interval - time_since_batch_creation)
142
140
  end
143
141
  end
144
142
  end
@@ -147,10 +145,7 @@ module Google
147
145
  def push_batch_request!
148
146
  return unless @batch
149
147
 
150
- request = @batch.request
151
- Concurrent::Future.new(executor: @stream.push_thread_pool) do
152
- @stream.push request
153
- end.execute
148
+ @stream.push @batch.request
154
149
 
155
150
  @batch = nil
156
151
  @batch_created_at = nil
@@ -0,0 +1,251 @@
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 "monitor"
17
+ require "concurrent"
18
+
19
+ module Google
20
+ module Cloud
21
+ module Pubsub
22
+ class Subscriber
23
+ ##
24
+ # @private
25
+ # # AsyncUnaryPusher
26
+ #
27
+ class AsyncUnaryPusher
28
+ include MonitorMixin
29
+
30
+ attr_reader :batch
31
+ attr_reader :max_bytes, :interval
32
+
33
+ def initialize stream, max_bytes: 10000000, interval: 1.0
34
+ @stream = stream
35
+
36
+ @max_bytes = max_bytes
37
+ @interval = interval
38
+
39
+ @cond = new_cond
40
+
41
+ # init MonitorMixin
42
+ super()
43
+ end
44
+
45
+ def acknowledge ack_ids
46
+ return true if ack_ids.empty?
47
+
48
+ synchronize do
49
+ ack_ids.each do |ack_id|
50
+ if @batch.nil?
51
+ @batch = Batch.new max_bytes: @max_bytes
52
+ @batch.ack ack_id
53
+ else
54
+ unless @batch.try_ack ack_id
55
+ push_batch_request!
56
+
57
+ @batch = Batch.new max_bytes: @max_bytes
58
+ @batch.ack ack_id
59
+ end
60
+ end
61
+
62
+ @batch_created_at ||= Time.now
63
+ @background_thread ||= Thread.new { run_background }
64
+
65
+ push_batch_request! if @batch.ready?
66
+ end
67
+
68
+ @cond.signal
69
+ end
70
+
71
+ nil
72
+ end
73
+
74
+ def delay deadline, ack_ids
75
+ return true if ack_ids.empty?
76
+
77
+ synchronize do
78
+ ack_ids.each do |ack_id|
79
+ if @batch.nil?
80
+ @batch = Batch.new max_bytes: @max_bytes
81
+ @batch.delay deadline, ack_id
82
+ else
83
+ unless @batch.try_delay deadline, ack_id
84
+ push_batch_request!
85
+
86
+ @batch = Batch.new max_bytes: @max_bytes
87
+ @batch.delay deadline, ack_id
88
+ end
89
+ end
90
+
91
+ @batch_created_at ||= Time.now
92
+ @background_thread ||= Thread.new { run_background }
93
+
94
+ push_batch_request! if @batch.ready?
95
+ end
96
+
97
+ @cond.signal
98
+ end
99
+
100
+ nil
101
+ end
102
+
103
+ def stop
104
+ synchronize do
105
+ @stopped = true
106
+
107
+ # Stop any background activity, clean up happens in wait!
108
+ @background_thread.kill if @background_thread
109
+ end
110
+
111
+ push_batch_request!
112
+ end
113
+
114
+ def started?
115
+ !stopped?
116
+ end
117
+
118
+ def stopped?
119
+ synchronize { @stopped }
120
+ end
121
+
122
+ protected
123
+
124
+ def run_background
125
+ synchronize do
126
+ until @stopped
127
+ if @batch.nil?
128
+ @cond.wait
129
+ next
130
+ end
131
+
132
+ time_since_batch_creation = Time.now - @batch_created_at
133
+ if time_since_batch_creation > @interval
134
+ # interval met, publish the batch...
135
+ 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)
140
+ end
141
+ end
142
+ end
143
+ end
144
+
145
+ def push_batch_request!
146
+ return unless @batch
147
+
148
+ service = @stream.subscriber.service
149
+ name = @stream.subscriber.subscription_name
150
+
151
+ if @batch.ack?
152
+ ack_ids = @batch.ack_ids
153
+ Concurrent::Future.new(executor: @stream.push_thread_pool) do
154
+ service.acknowledge name, *ack_ids
155
+ end.execute
156
+ end
157
+ if @batch.delay?
158
+ @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
162
+ end
163
+ end
164
+
165
+ @batch = nil
166
+ @batch_created_at = nil
167
+ end
168
+
169
+ class Batch
170
+ attr_reader :max_bytes, :request
171
+
172
+ def initialize max_bytes: 10000000
173
+ @max_bytes = max_bytes
174
+ @request = Google::Pubsub::V1::StreamingPullRequest.new
175
+ @total_message_bytes = 0
176
+ end
177
+
178
+ def ack ack_id
179
+ @request.ack_ids << ack_id
180
+ @total_message_bytes += addl_ack_bytes ack_id
181
+ end
182
+
183
+ def try_ack ack_id
184
+ addl_bytes = addl_ack_bytes ack_id
185
+ return false if total_message_bytes + addl_bytes >= @max_bytes
186
+
187
+ ack ack_id
188
+ true
189
+ end
190
+
191
+ def addl_ack_bytes ack_id
192
+ ack_id.bytesize + 2
193
+ end
194
+
195
+ def delay deadline, ack_id
196
+ @request.modify_deadline_seconds << deadline
197
+ @request.modify_deadline_ack_ids << ack_id
198
+ @total_message_bytes += addl_delay_bytes deadline, ack_id
199
+ end
200
+
201
+ def try_delay deadline, ack_id
202
+ addl_bytes = addl_delay_bytes deadline, ack_id
203
+ return false if total_message_bytes + addl_bytes >= @max_bytes
204
+
205
+ delay deadline, ack_id
206
+ true
207
+ end
208
+
209
+ def addl_delay_bytes deadline, ack_id
210
+ bytes_for_int(deadline) + ack_id.bytesize + 4
211
+ end
212
+
213
+ def bytes_for_int num
214
+ # Ruby 2.0 does not have Integer#bit_length
215
+ return [num].pack("s").bytesize unless num.respond_to? :bit_length
216
+
217
+ (num.bit_length / 8.0).ceil
218
+ end
219
+
220
+ def ready?
221
+ total_message_bytes >= @max_bytes
222
+ end
223
+
224
+ def ack?
225
+ @request.ack_ids.any?
226
+ end
227
+
228
+ def delay?
229
+ @request.modify_deadline_ack_ids.any?
230
+ end
231
+
232
+ def ack_ids
233
+ @request.ack_ids
234
+ end
235
+
236
+ def modify_deadline_hash
237
+ grouped_hash = @request.modify_deadline_ack_ids.zip(
238
+ @request.modify_deadline_seconds
239
+ ).group_by { |_ack_id, seconds| seconds }
240
+ Hash[grouped_hash.map { |k, v| [k, v.map(&:first)] }]
241
+ end
242
+
243
+ def total_message_bytes
244
+ @total_message_bytes
245
+ end
246
+ end
247
+ end
248
+ end
249
+ end
250
+ end
251
+ end
@@ -13,7 +13,7 @@
13
13
  # limitations under the License.
14
14
 
15
15
 
16
- require "google/cloud/pubsub/subscriber/async_pusher"
16
+ require "google/cloud/pubsub/subscriber/async_unary_pusher"
17
17
  require "google/cloud/pubsub/subscriber/enumerator_queue"
18
18
  require "google/cloud/pubsub/service"
19
19
  require "google/cloud/errors"
@@ -53,6 +53,15 @@ module Google
53
53
  @push_thread_pool = Concurrent::FixedThreadPool.new \
54
54
  subscriber.push_threads
55
55
 
56
+ @stream_keepalive_task = Concurrent::TimerTask.new(
57
+ execution_interval: 30
58
+ ) do
59
+ # push empty request every 30 seconds to keep stream alive
60
+ unless inventory.empty?
61
+ push Google::Pubsub::V1::StreamingPullRequest.new
62
+ end
63
+ end.execute
64
+
56
65
  super() # to init MonitorMixin
57
66
  end
58
67
 
@@ -98,14 +107,7 @@ module Google
98
107
 
99
108
  # Once all the callbacks are complete, we can stop the publisher
100
109
  # and send the final request to the steeam.
101
- if @async_pusher
102
- request = @async_pusher.stop
103
- if request
104
- Concurrent::Future.new(executor: @push_thread_pool) do
105
- @request_queue.push request
106
- end.execute
107
- end
108
- end
110
+ @async_pusher.stop if @async_pusher # will push current batch
109
111
 
110
112
  # Close the push thread pool now that the pusher is closed.
111
113
  @push_thread_pool.shutdown
@@ -125,7 +127,7 @@ module Google
125
127
  return true if ack_ids.empty?
126
128
 
127
129
  synchronize do
128
- @async_pusher ||= AsyncPusher.new self
130
+ @async_pusher ||= AsyncUnaryPusher.new self
129
131
  @async_pusher.acknowledge ack_ids
130
132
  @inventory.remove ack_ids
131
133
  unpause_streaming!
@@ -141,7 +143,7 @@ module Google
141
143
  return true if mod_ack_ids.empty?
142
144
 
143
145
  synchronize do
144
- @async_pusher ||= AsyncPusher.new self
146
+ @async_pusher ||= AsyncUnaryPusher.new self
145
147
  @async_pusher.delay deadline, mod_ack_ids
146
148
  @inventory.remove mod_ack_ids
147
149
  unpause_streaming!
@@ -168,7 +170,7 @@ module Google
168
170
  synchronize do
169
171
  return true if @inventory.empty?
170
172
 
171
- @async_pusher ||= AsyncPusher.new self
173
+ @async_pusher ||= AsyncUnaryPusher.new self
172
174
  @async_pusher.delay subscriber.deadline, @inventory.ack_ids
173
175
  end
174
176
 
@@ -211,7 +213,7 @@ module Google
211
213
 
212
214
  synchronize do
213
215
  # Create receipt of received messages reception
214
- @async_pusher ||= AsyncPusher.new self
216
+ @async_pusher ||= AsyncUnaryPusher.new self
215
217
  @async_pusher.delay subscriber.deadline, received_ack_ids
216
218
 
217
219
  # Add received messages to inventory
@@ -155,10 +155,10 @@ module Google
155
155
  Subscription.from_grpc grpc, service
156
156
  end)
157
157
  token = grpc_list.next_page_token
158
- token = nil if token == ""
159
- subs.instance_variable_set "@token", token
160
- subs.instance_variable_set "@service", service
161
- subs.instance_variable_set "@max", max
158
+ token = nil if token == "".freeze
159
+ subs.instance_variable_set :@token, token
160
+ subs.instance_variable_set :@service, service
161
+ subs.instance_variable_set :@max, max
162
162
  subs
163
163
  end
164
164
 
@@ -170,11 +170,11 @@ module Google
170
170
  Subscription.new_lazy grpc, service
171
171
  end)
172
172
  token = grpc_list.next_page_token
173
- token = nil if token == ""
174
- subs.instance_variable_set "@token", token
175
- subs.instance_variable_set "@service", service
176
- subs.instance_variable_set "@topic", topic
177
- subs.instance_variable_set "@max", max
173
+ token = nil if token == "".freeze
174
+ subs.instance_variable_set :@token, token
175
+ subs.instance_variable_set :@service, service
176
+ subs.instance_variable_set :@topic, topic
177
+ subs.instance_variable_set :@max, max
178
178
  subs
179
179
  end
180
180
 
@@ -149,10 +149,10 @@ module Google
149
149
  Topic.from_grpc grpc, service
150
150
  end)
151
151
  token = grpc_list.next_page_token
152
- token = nil if token == ""
153
- topics.instance_variable_set "@token", token
154
- topics.instance_variable_set "@service", service
155
- topics.instance_variable_set "@max", max
152
+ token = nil if token == "".freeze
153
+ topics.instance_variable_set :@token, token
154
+ topics.instance_variable_set :@service, service
155
+ topics.instance_variable_set :@max, max
156
156
  topics
157
157
  end
158
158
 
@@ -17,7 +17,7 @@ module Google
17
17
  # rubocop:disable LineLength
18
18
 
19
19
  ##
20
- # # Ruby Client for Google Cloud Pub/Sub API ([Alpha](https://github.com/GoogleCloudPlatform/google-cloud-ruby#versioning))
20
+ # # Ruby Client for Google Cloud Pub/Sub API ([Beta](https://github.com/GoogleCloudPlatform/google-cloud-ruby#versioning))
21
21
  #
22
22
  # [Google Cloud Pub/Sub API][Product Documentation]:
23
23
  # Provides reliable, many-to-many, asynchronous messaging between applications.
@@ -72,4 +72,4 @@ module Google
72
72
  end
73
73
  end
74
74
  end
75
- end
75
+ end
@@ -16,7 +16,7 @@
16
16
  module Google
17
17
  module Cloud
18
18
  module Pubsub
19
- VERSION = "0.30.2".freeze
19
+ VERSION = "0.31.1".freeze
20
20
  end
21
21
  end
22
22
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: google-cloud-pubsub
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.30.2
4
+ version: 0.31.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Moore
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2018-04-02 00:00:00.000000000 Z
12
+ date: 2018-08-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: google-cloud-core
@@ -219,7 +219,8 @@ files:
219
219
  - lib/google/cloud/pubsub/snapshot.rb
220
220
  - lib/google/cloud/pubsub/snapshot/list.rb
221
221
  - lib/google/cloud/pubsub/subscriber.rb
222
- - lib/google/cloud/pubsub/subscriber/async_pusher.rb
222
+ - lib/google/cloud/pubsub/subscriber/async_stream_pusher.rb
223
+ - lib/google/cloud/pubsub/subscriber/async_unary_pusher.rb
223
224
  - lib/google/cloud/pubsub/subscriber/enumerator_queue.rb
224
225
  - lib/google/cloud/pubsub/subscriber/stream.rb
225
226
  - lib/google/cloud/pubsub/subscription.rb
@@ -259,7 +260,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
259
260
  version: '0'
260
261
  requirements: []
261
262
  rubyforge_project:
262
- rubygems_version: 2.7.6
263
+ rubygems_version: 2.7.7
263
264
  signing_key:
264
265
  specification_version: 4
265
266
  summary: API Client library for Google Cloud Pub/Sub