google-cloud-pubsub 1.0.2 → 1.1.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8d3c2b3976af69e59bdb1ea9653f42164db682ce28a929b5325d760c46bab4aa
4
- data.tar.gz: 0f922862ba91d39e1ba8f55a66d2a6699392157ed850e129ed127dc9f63ac1d5
3
+ metadata.gz: 60202a1d96c472dc3bb05992db2ed19da1e34077ceeb5e0a066126a69d569f30
4
+ data.tar.gz: b671179cf63643ec45598fe63b29440504f2d24ce9f2d8495ec0e16e66838809
5
5
  SHA512:
6
- metadata.gz: d33fdcdb157fa0795e6fc28517ccdd26b8b03b3380dd96bd6f931063eae3ac30a5c4d3b5e9dafd32bbc93ee76e4db3544611c4b1ac9a63ad6068422c9bab466e
7
- data.tar.gz: b8218aceaa79d35777e540a43764e7e49474e5dc393c508384f12e4dff09e7d5e1470a8d5a9f2ed6bf96c17d54c63be8489aefbf32babccfeb57a15035867521
6
+ metadata.gz: 01ab09622f6773bfe6a0a5b96171eebb348c71dffd13b06d48eb1754d7cfde3464f81d51051f4a60d5d72c7e39b1b9e746b8417f0d9b86b50dd54280978f3ca4
7
+ data.tar.gz: c0eeb49f436cd8e385ce16b37f5a93445dd29417729624edd572e5a5bc2454c8b3e4504edba9cd73ffe227be64b4b68bfcadceb6e65983b12dfccb222a2879e2
@@ -1,5 +1,24 @@
1
1
  # Release History
2
2
 
3
+ ### 1.1.0 / 2019-10-23
4
+
5
+ #### Features
6
+
7
+ * Add support for Ordering Keys
8
+ * Google Cloud Pub/Sub ordering keys provide the ability to ensure related
9
+ messages are sent to subscribers in the order in which they were published.
10
+ The service guarantees that, for a given ordering key and publisher, messages
11
+ are sent to subscribers in the order in which they were published.
12
+ * Note: At the time of this release, ordering keys are not yet publicly enabled
13
+ and requires special project enablements.
14
+ * Add Google::Cloud::PubSub::Topic#enable_message_ordering! method.
15
+ * Add Google::Cloud::PubSub::Topic#message_ordering? method.
16
+ * Add ordering_key argument to Google::Cloud::PubSub::Topic#publish_async method.
17
+ * Add Google::Cloud::PubSub::Topic#resume_publish method.
18
+ * Add message_ordering argument to Google::Cloud::PubSub::Topic#subscribe method.
19
+ * Add Google::Cloud::PubSub::Subscription#message_ordering? method.
20
+ * Update Ruby dependency to minimum of 2.4.
21
+
3
22
  ### 1.0.2 / 2019-10-10
4
23
 
5
24
  #### Bug Fixes
@@ -24,7 +24,7 @@ be able to accept your pull requests.
24
24
  In order to use the google-cloud-pubsub console and run the project's tests,
25
25
  there is a small amount of setup:
26
26
 
27
- 1. Install Ruby. google-cloud-pubsub requires Ruby 2.3+. You may choose to
27
+ 1. Install Ruby. google-cloud-pubsub requires Ruby 2.4+. You may choose to
28
28
  manage your Ruby and gem installations with [RVM](https://rvm.io/),
29
29
  [rbenv](https://github.com/rbenv/rbenv), or
30
30
  [chruby](https://github.com/postmodern/chruby).
@@ -161,7 +161,7 @@ msgs = topic.publish do |batch|
161
161
  end
162
162
  ```
163
163
 
164
- ## Receiving messages
164
+ ## Receiving Messages
165
165
 
166
166
  Messages can be streamed from a subscription with a subscriber object that is
167
167
  created using `listen`. (See {Google::Cloud::PubSub::Subscription#listen
@@ -316,6 +316,88 @@ received_messages = sub.pull
316
316
  sub.modify_ack_deadline 120, received_messages
317
317
  ```
318
318
 
319
+ ## Using Ordering Keys
320
+
321
+ Google Cloud Pub/Sub ordering keys provide the ability to ensure related
322
+ messages are sent to subscribers in the order in which they were published.
323
+ Messages can be tagged with an ordering key, a string that identifies related
324
+ messages for which publish order should be respected. The service guarantees
325
+ that, for a given ordering key and publisher, messages are sent to subscribers
326
+ in the order in which they were published. Ordering does not require sacrificing
327
+ high throughput or scalability, as the service automatically distributes
328
+ messages for different ordering keys across subscribers.
329
+
330
+ Note: At the time of this release, ordering keys are not yet publicly enabled
331
+ and requires special project enablements.
332
+
333
+ ### Publishing Ordered Messages
334
+
335
+ To use ordering keys when publishing messages, a call to
336
+ {Google::Cloud::PubSub::Topic#enable_message_ordering!
337
+ Topic#enable_message_ordering!} must be made and the `ordering_key` argument
338
+ must be provided when calling {Google::Cloud::PubSub::Topic#publish_async
339
+ Topic#publish_async}.
340
+
341
+ ```ruby
342
+ require "google/cloud/pubsub"
343
+
344
+ pubsub = Google::Cloud::PubSub.new
345
+
346
+ topic = pubsub.topic "my-ordered-topic"
347
+
348
+ # Ensure that message ordering is enabled.
349
+ topic.enable_message_ordering!
350
+
351
+ # Publish an ordered message with an ordering key.
352
+ topic.publish_async "task completed",
353
+ ordering_key: "task-key"
354
+
355
+ # Shut down the publisher when ready to stop publishing messages.
356
+ topic.async_publisher.stop.wait!
357
+ ```
358
+
359
+ ### Handling errors with Ordered Keys
360
+
361
+ Ordered messages that fail to publish to the Pub/Sub API due to error will put
362
+ the `ordering_key` in a failed state, and future calls to
363
+ {Google::Cloud::PubSub::Topic#publish_async Topic#publish_async} with the
364
+ `ordering_key` will raise {Google::Cloud::PubSub::OrderingKeyError
365
+ OrderingKeyError}. To allow future messages with the `ordering_key` to be
366
+ published, the `ordering_key` must be passed to
367
+ {Google::Cloud::PubSub::Topic#resume_publish Topic#resume_publish}.
368
+
369
+ ### Receiving Ordered Messages
370
+
371
+ To use ordering keys when subscribing to messages, the subscription must be
372
+ created with message ordering enabled (See
373
+ {Google::Cloud::PubSub::Topic#subscribe Topic#subscribe} and
374
+ {Google::Cloud::PubSub::Subscription#message_ordering?
375
+ Subscription#message_ordering?}) before calling
376
+ {Google::Cloud::PubSub::Subscription#listen Subscription#listen}. When enabled,
377
+ the subscriber will deliver messages with the same `ordering_key` in the order
378
+ they were published.
379
+
380
+ ```ruby
381
+ require "google/cloud/pubsub"
382
+
383
+ pubsub = Google::Cloud::PubSub.new
384
+
385
+ sub = pubsub.subscription "my-ordered-topic-sub"
386
+ sub.message_ordering? #=> true
387
+
388
+ subscriber = sub.listen do |received_message|
389
+ # Messsages with the same ordering_key are received
390
+ # in the order in which they were published.
391
+ received_message.acknowledge!
392
+ end
393
+
394
+ # Start background threads that will call block passed to listen.
395
+ subscriber.start
396
+
397
+ # Shut down the subscriber when ready to stop receiving messages.
398
+ subscriber.stop.wait!
399
+ ```
400
+
319
401
  ## Minimizing API calls before receiving and acknowledging messages
320
402
 
321
403
  A subscription object can be created without making any API calls by providing
@@ -64,9 +64,7 @@ module Google
64
64
  #
65
65
  def pubsub scope: nil, timeout: nil, client_config: nil
66
66
  timeout ||= @timeout
67
- Google::Cloud.pubsub @project, @keyfile, scope: scope,
68
- timeout: timeout,
69
- client_config: client_config
67
+ Google::Cloud.pubsub @project, @keyfile, scope: scope, timeout: timeout, client_config: client_config
70
68
  end
71
69
 
72
70
  ##
@@ -108,10 +106,8 @@ module Google
108
106
  def self.pubsub project_id = nil, credentials = nil, scope: nil,
109
107
  timeout: nil, client_config: nil
110
108
  require "google/cloud/pubsub"
111
- Google::Cloud::PubSub.new project_id: project_id,
112
- credentials: credentials,
113
- scope: scope, timeout: timeout,
114
- client_config: client_config
109
+ Google::Cloud::PubSub.new project_id: project_id, credentials: credentials,
110
+ scope: scope, timeout: timeout, client_config: client_config
115
111
  end
116
112
  end
117
113
  end
@@ -123,8 +119,7 @@ Google::Cloud.configure.add_config! :pubsub do |config|
123
119
  end
124
120
  default_creds = Google::Cloud::Config.deferred do
125
121
  Google::Cloud::Config.credentials_from_env(
126
- "PUBSUB_CREDENTIALS", "PUBSUB_CREDENTIALS_JSON",
127
- "PUBSUB_KEYFILE", "PUBSUB_KEYFILE_JSON"
122
+ "PUBSUB_CREDENTIALS", "PUBSUB_CREDENTIALS_JSON", "PUBSUB_KEYFILE", "PUBSUB_KEYFILE_JSON"
128
123
  )
129
124
  end
130
125
  default_emulator = Google::Cloud::Config.deferred do
@@ -133,15 +128,12 @@ Google::Cloud.configure.add_config! :pubsub do |config|
133
128
 
134
129
  config.add_field! :project_id, default_project, match: String, allow_nil: true
135
130
  config.add_alias! :project, :project_id
136
- config.add_field! :credentials, default_creds,
137
- match: [String, Hash, Google::Auth::Credentials],
138
- allow_nil: true
131
+ config.add_field! :credentials, default_creds, match: [String, Hash, Google::Auth::Credentials], allow_nil: true
139
132
  config.add_alias! :keyfile, :credentials
140
133
  config.add_field! :scope, nil, match: [String, Array]
141
134
  config.add_field! :timeout, nil, match: Integer
142
135
  config.add_field! :client_config, nil, match: Hash
143
- config.add_field! :emulator_host, default_emulator,
144
- match: String, allow_nil: true
136
+ config.add_field! :emulator_host, default_emulator, match: String, allow_nil: true
145
137
  config.add_field! :on_error, nil, match: Proc
146
138
  config.add_field! :endpoint, nil, match: String
147
139
  end
@@ -77,9 +77,8 @@ module Google
77
77
  # topic = pubsub.topic "my-topic"
78
78
  # topic.publish "task completed"
79
79
  #
80
- def self.new project_id: nil, credentials: nil, scope: nil, timeout: nil,
81
- client_config: nil, endpoint: nil, emulator_host: nil,
82
- project: nil, keyfile: nil
80
+ def self.new project_id: nil, credentials: nil, scope: nil, timeout: nil, client_config: nil, endpoint: nil,
81
+ emulator_host: nil, project: nil, keyfile: nil
83
82
  project_id ||= (project || default_project_id)
84
83
  scope ||= configure.scope
85
84
  timeout ||= configure.timeout
@@ -93,9 +92,7 @@ module Google
93
92
 
94
93
  return PubSub::Project.new(
95
94
  PubSub::Service.new(
96
- project_id, :this_channel_is_insecure,
97
- host: emulator_host, timeout: timeout,
98
- client_config: client_config
95
+ project_id, :this_channel_is_insecure, host: emulator_host, timeout: timeout, client_config: client_config
99
96
  )
100
97
  )
101
98
  end
@@ -105,17 +102,13 @@ module Google
105
102
  credentials = PubSub::Credentials.new credentials, scope: scope
106
103
  end
107
104
 
108
- if credentials.respond_to? :project_id
109
- project_id ||= credentials.project_id
110
- end
105
+ project_id ||= credentials.project_id if credentials.respond_to? :project_id
111
106
  project_id = project_id.to_s # Always cast to a string
112
107
  raise ArgumentError, "project_id is missing" if project_id.empty?
113
108
 
114
109
  PubSub::Project.new(
115
110
  PubSub::Service.new(
116
- project_id, credentials, timeout: timeout,
117
- host: endpoint,
118
- client_config: client_config
111
+ project_id, credentials, timeout: timeout, host: endpoint, client_config: client_config
119
112
  )
120
113
  )
121
114
  end
@@ -15,8 +15,11 @@
15
15
 
16
16
  require "monitor"
17
17
  require "concurrent"
18
+ require "google/cloud/pubsub/errors"
19
+ require "google/cloud/pubsub/async_publisher/batch"
18
20
  require "google/cloud/pubsub/publish_result"
19
21
  require "google/cloud/pubsub/service"
22
+ require "google/cloud/pubsub/convert"
20
23
 
21
24
  module Google
22
25
  module Cloud
@@ -68,8 +71,7 @@ module Google
68
71
 
69
72
  ##
70
73
  # @private Create a new instance of the object.
71
- def initialize topic_name, service, max_bytes: 10000000,
72
- max_messages: 1000, interval: 0.25, threads: {}
74
+ def initialize topic_name, service, max_bytes: 10_000_000, max_messages: 1000, interval: 0.25, threads: {}
73
75
  @topic_name = service.topic_path topic_name
74
76
  @service = service
75
77
 
@@ -79,6 +81,14 @@ module Google
79
81
  @publish_threads = (threads[:publish] || 4).to_i
80
82
  @callback_threads = (threads[:callback] || 8).to_i
81
83
 
84
+ @published_at = nil
85
+ @publish_thread_pool = Concurrent::ThreadPoolExecutor.new max_threads: @publish_threads
86
+ @callback_thread_pool = Concurrent::ThreadPoolExecutor.new max_threads: @callback_threads
87
+ @thread = Thread.new { run_background }
88
+
89
+ @ordered = false
90
+ @batches = {}
91
+
82
92
  @cond = new_cond
83
93
 
84
94
  # init MonitorMixin
@@ -89,29 +99,45 @@ module Google
89
99
  # Add a message to the async publisher to be published to the topic.
90
100
  # Messages will be collected in batches and published together.
91
101
  # See {Google::Cloud::PubSub::Topic#publish_async}
92
- def publish data = nil, attributes = {}, &block
93
- msg = create_pubsub_message data, attributes
102
+ #
103
+ # @param [String, File] data The message payload. This will be converted
104
+ # to bytes encoded as ASCII-8BIT.
105
+ # @param [Hash] attributes Optional attributes for the message.
106
+ # @param [String] ordering_key Identifies related messages for which
107
+ # publish order should be respected.
108
+ # @yield [result] the callback for when the message has been published
109
+ # @yieldparam [PublishResult] result the result of the asynchronous
110
+ # publish
111
+ # @raise [Google::Cloud::PubSub::AsyncPublisherStopped] when the
112
+ # publisher is stopped. (See {#stop} and {#stopped?}.)
113
+ # @raise [Google::Cloud::PubSub::OrderedMessagesDisabled] when
114
+ # publishing a message with an `ordering_key` but ordered messages are
115
+ # not enabled. (See {#message_ordering?} and
116
+ # {#enable_message_ordering!}.)
117
+ # @raise [Google::Cloud::PubSub::OrderingKeyError] when publishing a
118
+ # message with an `ordering_key` that has already failed when
119
+ # publishing. Use {#resume_publish} to allow this `ordering_key` to be
120
+ # published again.
121
+ #
122
+ def publish data = nil, attributes = nil, ordering_key: nil, **extra_attrs, &callback
123
+ msg = Convert.pubsub_message data, attributes, ordering_key, extra_attrs
94
124
 
95
125
  synchronize do
96
- raise "Can't publish when stopped." if @stopped
97
-
98
- if @batch.nil?
99
- @batch ||= Batch.new self
100
- @batch.add msg, block
101
- else
102
- unless @batch.try_add msg, block
103
- publish_batch!
104
- @batch = Batch.new self
105
- @batch.add msg, block
106
- end
126
+ raise AsyncPublisherStopped if @stopped
127
+ raise OrderedMessagesDisabled if !@ordered && !msg.ordering_key.empty? # default is empty string
128
+
129
+ batch = resolve_batch_for_message msg
130
+ raise OrderingKeyError, batch.ordering_key if batch.canceled?
131
+ batch_action = batch.add msg, callback
132
+ if batch_action == :full
133
+ publish_batches!
134
+ elsif @published_at.nil?
135
+ # Set initial time to now to start the background counter
136
+ @published_at = Time.now
107
137
  end
108
-
109
- init_resources!
110
-
111
- publish_batch! if @batch.ready?
112
-
113
138
  @cond.signal
114
139
  end
140
+
115
141
  nil
116
142
  end
117
143
 
@@ -127,9 +153,9 @@ module Google
127
153
  break if @stopped
128
154
 
129
155
  @stopped = true
130
- publish_batch!
156
+ publish_batches! stop: true
131
157
  @cond.signal
132
- @publish_thread_pool.shutdown if @publish_thread_pool
158
+ @publish_thread_pool.shutdown
133
159
  end
134
160
 
135
161
  self
@@ -149,14 +175,10 @@ module Google
149
175
  # @return [AsyncPublisher] returns self so calls can be chained.
150
176
  def wait! timeout = nil
151
177
  synchronize do
152
- if @publish_thread_pool
153
- @publish_thread_pool.wait_for_termination timeout
154
- end
178
+ @publish_thread_pool.wait_for_termination timeout
155
179
 
156
- if @callback_thread_pool
157
- @callback_thread_pool.shutdown
158
- @callback_thread_pool.wait_for_termination timeout
159
- end
180
+ @callback_thread_pool.shutdown
181
+ @callback_thread_pool.wait_for_termination timeout
160
182
  end
161
183
 
162
184
  self
@@ -185,7 +207,7 @@ module Google
185
207
  # @return [AsyncPublisher] returns self so calls can be chained.
186
208
  def flush
187
209
  synchronize do
188
- publish_batch!
210
+ publish_batches!
189
211
  @cond.signal
190
212
  end
191
213
 
@@ -208,33 +230,63 @@ module Google
208
230
  synchronize { @stopped }
209
231
  end
210
232
 
211
- protected
233
+ ##
234
+ # Enables message ordering for messages with ordering keys. When
235
+ # enabled, messages published with the same `ordering_key` will be
236
+ # delivered in the order they were published.
237
+ #
238
+ # See {#message_ordering?}. See {Topic#publish_async},
239
+ # {Subscription#listen}, and {Message#ordering_key}.
240
+ #
241
+ def enable_message_ordering!
242
+ synchronize { @ordered = true }
243
+ end
212
244
 
213
- # rubocop:disable Naming/MemoizedInstanceVariableName
245
+ ##
246
+ # Whether message ordering for messages with ordering keys has been
247
+ # enabled. When enabled, messages published with the same `ordering_key`
248
+ # will be delivered in the order they were published. When disabled,
249
+ # messages may be delivered in any order.
250
+ #
251
+ # See {#enable_message_ordering!}. See {Topic#publish_async},
252
+ # {Subscription#listen}, and {Message#ordering_key}.
253
+ #
254
+ # @return [Boolean]
255
+ #
256
+ def message_ordering?
257
+ synchronize { @ordered }
258
+ end
214
259
 
215
- def init_resources!
216
- @first_published_at ||= Time.now
217
- @publish_thread_pool ||= Concurrent::ThreadPoolExecutor.new \
218
- max_threads: @publish_threads
219
- @callback_thread_pool ||= Concurrent::ThreadPoolExecutor.new \
220
- max_threads: @callback_threads
221
- @thread ||= Thread.new { run_background }
260
+ ##
261
+ # Resume publishing ordered messages for the provided ordering key.
262
+ #
263
+ # @param [String] ordering_key Identifies related messages for which
264
+ # publish order should be respected.
265
+ #
266
+ # @return [boolean] `true` when resumed, `false` otherwise.
267
+ #
268
+ def resume_publish ordering_key
269
+ synchronize do
270
+ batch = resolve_batch_for_ordering_key ordering_key
271
+ return if batch.nil?
272
+ batch.resume!
273
+ end
222
274
  end
223
275
 
224
- # rubocop:enable Naming/MemoizedInstanceVariableName
276
+ protected
225
277
 
226
278
  def run_background
227
279
  synchronize do
228
280
  until @stopped
229
- if @batch.nil?
281
+ if @published_at.nil?
230
282
  @cond.wait
231
283
  next
232
284
  end
233
285
 
234
- time_since_first_publish = Time.now - @first_published_at
286
+ time_since_first_publish = Time.now - @published_at
235
287
  if time_since_first_publish > @interval
236
- # interval met, publish the batch...
237
- publish_batch!
288
+ # interval met, flush the batches...
289
+ publish_batches!
238
290
  @cond.wait
239
291
  else
240
292
  # still waiting for the interval to publish the batch...
@@ -245,40 +297,93 @@ module Google
245
297
  end
246
298
  end
247
299
 
248
- def publish_batch!
249
- return unless @batch
300
+ def resolve_batch_for_message msg
301
+ @batches[msg.ordering_key] ||= Batch.new self, msg.ordering_key
302
+ end
250
303
 
251
- publish_batch_async @topic_name, @batch
252
- @batch = nil
253
- @first_published_at = nil
304
+ def resolve_batch_for_ordering_key ordering_key
305
+ @batches[ordering_key]
306
+ end
307
+
308
+ def publish_batches! stop: nil
309
+ @batches.reject! { |_ordering_key, batch| batch.empty? }
310
+ @batches.values.each do |batch|
311
+ ready = batch.publish! stop: stop
312
+ publish_batch_async @topic_name, batch if ready
313
+ end
314
+ # Set published_at to nil to wait indefinitely
315
+ @published_at = nil
254
316
  end
255
317
 
256
318
  def publish_batch_async topic_name, batch
319
+ # TODO: raise unless @publish_thread_pool.running?
257
320
  return unless @publish_thread_pool.running?
258
321
 
259
322
  Concurrent::Promises.future_on(
260
323
  @publish_thread_pool, topic_name, batch
261
- ) do |t_name, btch|
262
- publish_batch_sync t_name, btch
263
- end
324
+ ) { |t, b| publish_batch_sync t, b }
264
325
  end
265
326
 
327
+ # rubocop:disable Metrics/AbcSize
328
+ # rubocop:disable Metrics/MethodLength
329
+
266
330
  def publish_batch_sync topic_name, batch
267
- grpc = @service.publish topic_name, batch.messages
268
- batch.items.zip Array(grpc.message_ids) do |item, id|
269
- next unless item.callback
331
+ # The only batch methods that are safe to call from the loop are
332
+ # rebalance! and reset! because they are the only methods that are
333
+ # synchronized.
334
+ loop do
335
+ items = batch.rebalance!
336
+
337
+ unless items.empty?
338
+ grpc = @service.publish topic_name, items.map(&:msg)
339
+ items.zip Array(grpc.message_ids) do |item, id|
340
+ next unless item.callback
341
+
342
+ item.msg.message_id = id
343
+ publish_result = PublishResult.from_grpc item.msg
344
+ execute_callback_async item.callback, publish_result
345
+ end
346
+ end
270
347
 
271
- item.msg.message_id = id
272
- publish_result = PublishResult.from_grpc item.msg
273
- execute_callback_async item.callback, publish_result
348
+ break unless batch.reset!
274
349
  end
275
350
  rescue StandardError => e
276
- batch.items.each do |item|
351
+ items = batch.items
352
+
353
+ unless batch.ordering_key.empty?
354
+ retry if publish_batch_error_retryable? e
355
+ # Cancel the batch if the error is not to be retried.
356
+ begin
357
+ raise OrderingKeyError, batch.ordering_key
358
+ rescue OrderingKeyError => e
359
+ # The existing e variable is not set to OrderingKeyError
360
+ # Get all unsent messages for the callback
361
+ items = batch.cancel!
362
+ end
363
+ end
364
+
365
+ items.each do |item|
277
366
  next unless item.callback
278
367
 
279
368
  publish_result = PublishResult.from_error item.msg, e
280
369
  execute_callback_async item.callback, publish_result
281
370
  end
371
+
372
+ # publish will retry indefinitely, as long as there are unsent items.
373
+ retry if batch.reset!
374
+ end
375
+
376
+ # rubocop:enable Metrics/AbcSize
377
+ # rubocop:enable Metrics/MethodLength
378
+
379
+ PUBLISH_RETRY_ERRORS = [
380
+ GRPC::Cancelled, GRPC::DeadlineExceeded, GRPC::Internal,
381
+ GRPC::ResourceExhausted, GRPC::Unauthenticated, GRPC::Unavailable,
382
+ GRPC::Core::CallError
383
+ ].freeze
384
+
385
+ def publish_batch_error_retryable? error
386
+ PUBLISH_RETRY_ERRORS.any? { |klass| error.is_a? klass }
282
387
  end
283
388
 
284
389
  def execute_callback_async callback, publish_result
@@ -290,79 +395,6 @@ module Google
290
395
  cback.call p_result
291
396
  end
292
397
  end
293
-
294
- def create_pubsub_message data, attributes
295
- attributes ||= {}
296
- if data.is_a?(::Hash) && attributes.empty?
297
- attributes = data
298
- data = nil
299
- end
300
- # Convert IO-ish objects to strings
301
- if data.respond_to?(:read) && data.respond_to?(:rewind)
302
- data.rewind
303
- data = data.read
304
- end
305
- # Convert data to encoded byte array to match the protobuf defn
306
- data_bytes = \
307
- String(data).dup.force_encoding(Encoding::ASCII_8BIT).freeze
308
-
309
- # Convert attributes to strings to match the protobuf definition
310
- attributes = Hash[attributes.map { |k, v| [String(k), String(v)] }]
311
-
312
- Google::Cloud::PubSub::V1::PubsubMessage.new data: data_bytes,
313
- attributes: attributes
314
- end
315
-
316
- ##
317
- # @private
318
- class Batch
319
- attr_reader :messages, :callbacks
320
-
321
- def initialize publisher
322
- @publisher = publisher
323
- @messages = []
324
- @callbacks = []
325
- @total_message_bytes = publisher.topic_name.bytesize + 2
326
- end
327
-
328
- def add msg, callback
329
- @messages << msg
330
- @callbacks << callback
331
- @total_message_bytes += msg.to_proto.bytesize + 2
332
- end
333
-
334
- def try_add msg, callback
335
- new_message_count = total_message_count + 1
336
- new_message_bytes = total_message_bytes + msg.to_proto.bytesize + 2
337
- if new_message_count > @publisher.max_messages ||
338
- new_message_bytes >= @publisher.max_bytes
339
- return false
340
- end
341
- add msg, callback
342
- true
343
- end
344
-
345
- def ready?
346
- total_message_count >= @publisher.max_messages ||
347
- total_message_bytes >= @publisher.max_bytes
348
- end
349
-
350
- def total_message_count
351
- @messages.count
352
- end
353
-
354
- def total_message_bytes
355
- @total_message_bytes
356
- end
357
-
358
- def items
359
- @messages.zip(@callbacks).map do |msg, callback|
360
- Item.new msg, callback
361
- end
362
- end
363
-
364
- Item = Struct.new :msg, :callback
365
- end
366
398
  end
367
399
  end
368
400