google-cloud-pubsub 2.15.5 → 3.3.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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/AUTHENTICATION.md +12 -1
  3. data/CHANGELOG.md +129 -0
  4. data/OVERVIEW.md +189 -145
  5. data/lib/google/cloud/pubsub/admin_clients.rb +116 -0
  6. data/lib/google/cloud/pubsub/async_publisher.rb +20 -19
  7. data/lib/google/cloud/pubsub/batch_publisher.rb +7 -5
  8. data/lib/google/cloud/pubsub/convert.rb +1 -1
  9. data/lib/google/cloud/pubsub/errors.rb +3 -3
  10. data/lib/google/cloud/pubsub/flow_controller.rb +0 -2
  11. data/lib/google/cloud/pubsub/internal_logger.rb +76 -0
  12. data/lib/google/cloud/pubsub/message.rb +10 -11
  13. data/lib/google/cloud/pubsub/{subscriber → message_listener}/enumerator_queue.rb +1 -1
  14. data/lib/google/cloud/pubsub/{subscriber → message_listener}/inventory.rb +13 -10
  15. data/lib/google/cloud/pubsub/{subscriber → message_listener}/sequencer.rb +1 -1
  16. data/lib/google/cloud/pubsub/{subscriber → message_listener}/stream.rb +58 -17
  17. data/lib/google/cloud/pubsub/{subscriber → message_listener}/timed_unary_buffer.rb +29 -9
  18. data/lib/google/cloud/pubsub/message_listener.rb +413 -0
  19. data/lib/google/cloud/pubsub/project.rb +108 -523
  20. data/lib/google/cloud/pubsub/publisher.rb +424 -0
  21. data/lib/google/cloud/pubsub/received_message.rb +50 -45
  22. data/lib/google/cloud/pubsub/service.rb +48 -349
  23. data/lib/google/cloud/pubsub/subscriber.rb +442 -279
  24. data/lib/google/cloud/pubsub/version.rb +1 -1
  25. data/lib/google/cloud/pubsub.rb +51 -30
  26. data/lib/google-cloud-pubsub.rb +30 -10
  27. metadata +19 -183
  28. data/lib/google/cloud/pubsub/policy.rb +0 -188
  29. data/lib/google/cloud/pubsub/retry_policy.rb +0 -88
  30. data/lib/google/cloud/pubsub/schema/list.rb +0 -180
  31. data/lib/google/cloud/pubsub/schema.rb +0 -310
  32. data/lib/google/cloud/pubsub/snapshot/list.rb +0 -178
  33. data/lib/google/cloud/pubsub/snapshot.rb +0 -205
  34. data/lib/google/cloud/pubsub/subscription/list.rb +0 -205
  35. data/lib/google/cloud/pubsub/subscription/push_config.rb +0 -268
  36. data/lib/google/cloud/pubsub/subscription.rb +0 -1467
  37. data/lib/google/cloud/pubsub/topic/list.rb +0 -171
  38. data/lib/google/cloud/pubsub/topic.rb +0 -1100
@@ -18,6 +18,8 @@ require "google/cloud/pubsub/credentials"
18
18
  require "google/cloud/pubsub/convert"
19
19
  require "google/cloud/pubsub/version"
20
20
  require "google/cloud/pubsub/v1"
21
+ require "google/cloud/pubsub/admin_clients"
22
+ require "google/cloud/pubsub/internal_logger"
21
23
  require "securerandom"
22
24
 
23
25
  module Google
@@ -37,51 +39,63 @@ module Google
37
39
  # value to be replaced for unit testing.
38
40
  attr_accessor :client_id
39
41
 
42
+ attr_reader :universe_domain
43
+
44
+ ##
45
+ # @private The InternalLogger object.
46
+ attr_reader :logger
47
+
40
48
  ##
41
49
  # Creates a new Service instance.
42
- def initialize project, credentials, host: nil, timeout: nil
50
+ def initialize project, credentials, host: nil, timeout: nil, universe_domain: nil, logger: nil
43
51
  @project = project
44
52
  @credentials = credentials
45
53
  @host = host
46
54
  @timeout = timeout
47
55
  @client_id = SecureRandom.uuid.freeze
56
+ @universe_domain = universe_domain || ENV["GOOGLE_CLOUD_UNIVERSE_DOMAIN"] || "googleapis.com"
57
+ @logger = logger
48
58
  end
49
59
 
50
- def subscriber
51
- return mocked_subscriber if mocked_subscriber
52
- @subscriber ||= V1::Subscriber::Client.new do |config|
60
+ def subscription_admin
61
+ return mocked_subscription_admin if mocked_subscription_admin
62
+ @subscription_admin ||= SubscriptionAdmin::Client.new do |config|
53
63
  config.credentials = credentials if credentials
54
64
  override_client_config_timeouts config if timeout
55
65
  config.endpoint = host if host
66
+ config.universe_domain = universe_domain
56
67
  config.lib_name = "gccl"
57
68
  config.lib_version = Google::Cloud::PubSub::VERSION
58
69
  config.metadata = { "google-cloud-resource-prefix": "projects/#{@project}" }
59
70
  end
60
71
  end
61
- attr_accessor :mocked_subscriber
72
+ attr_accessor :mocked_subscription_admin
62
73
 
63
- def publisher
64
- return mocked_publisher if mocked_publisher
65
- @publisher ||= V1::Publisher::Client.new do |config|
74
+ def topic_admin
75
+ return mocked_topic_admin if mocked_topic_admin
76
+ @topic_admin ||= TopicAdmin::Client.new do |config|
66
77
  config.credentials = credentials if credentials
67
78
  override_client_config_timeouts config if timeout
68
79
  config.endpoint = host if host
80
+ config.universe_domain = universe_domain
69
81
  config.lib_name = "gccl"
70
82
  config.lib_version = Google::Cloud::PubSub::VERSION
71
83
  config.metadata = { "google-cloud-resource-prefix": "projects/#{@project}" }
72
84
  end
73
85
  end
74
- attr_accessor :mocked_publisher
86
+ attr_accessor :mocked_topic_admin
75
87
 
76
88
  def iam
77
89
  return mocked_iam if mocked_iam
78
- @iam ||= V1::IAMPolicy::Client.new do |config|
79
- config.credentials = credentials if credentials
80
- override_client_config_timeouts config if timeout
81
- config.endpoint = host if host
82
- config.lib_name = "gccl"
83
- config.lib_version = Google::Cloud::PubSub::VERSION
84
- config.metadata = { "google-cloud-resource-prefix": "projects/#{@project}" }
90
+ @iam ||= begin
91
+ iam = (@topic_admin || @subscription_admin || @schemas || topic_admin).iam_policy_client
92
+ iam.configure do |config|
93
+ override_client_config_timeouts config if timeout
94
+ config.lib_name = "gccl"
95
+ config.lib_version = Google::Cloud::PubSub::VERSION
96
+ config.metadata = { "google-cloud-resource-prefix": "projects/#{@project}" }
97
+ end
98
+ iam
85
99
  end
86
100
  end
87
101
  attr_accessor :mocked_iam
@@ -92,6 +106,7 @@ module Google
92
106
  config.credentials = credentials if credentials
93
107
  override_client_config_timeouts config if timeout
94
108
  config.endpoint = host if host
109
+ config.universe_domain = universe_domain
95
110
  config.lib_name = "gccl"
96
111
  config.lib_version = Google::Cloud::PubSub::VERSION
97
112
  config.metadata = { "google-cloud-resource-prefix": "projects/#{@project}" }
@@ -99,75 +114,6 @@ module Google
99
114
  end
100
115
  attr_accessor :mocked_schemas
101
116
 
102
- ##
103
- # Gets the configuration of a topic.
104
- # Since the topic only has the name attribute,
105
- # this method is only useful to check the existence of a topic.
106
- # If other attributes are added in the future,
107
- # they will be returned here.
108
- def get_topic topic_name, options = {}
109
- publisher.get_topic topic: topic_path(topic_name, options)
110
- end
111
-
112
- ##
113
- # Lists matching topics.
114
- def list_topics options = {}
115
- paged_enum = publisher.list_topics project: project_path(options),
116
- page_size: options[:max],
117
- page_token: options[:token]
118
-
119
- paged_enum.response
120
- end
121
-
122
- ##
123
- # Creates the given topic with the given name.
124
- def create_topic topic_name,
125
- labels: nil,
126
- kms_key_name: nil,
127
- persistence_regions: nil,
128
- schema_name: nil,
129
- message_encoding: nil,
130
- retention: nil,
131
- options: {}
132
- if persistence_regions
133
- message_storage_policy = Google::Cloud::PubSub::V1::MessageStoragePolicy.new(
134
- allowed_persistence_regions: Array(persistence_regions)
135
- )
136
- end
137
-
138
- if schema_name || message_encoding
139
- unless schema_name && message_encoding
140
- raise ArgumentError, "Schema settings must include both schema_name and message_encoding."
141
- end
142
- schema_settings = Google::Cloud::PubSub::V1::SchemaSettings.new(
143
- schema: schema_path(schema_name),
144
- encoding: message_encoding.to_s.upcase
145
- )
146
- end
147
-
148
- publisher.create_topic \
149
- name: topic_path(topic_name, options),
150
- labels: labels,
151
- kms_key_name: kms_key_name,
152
- message_storage_policy: message_storage_policy,
153
- schema_settings: schema_settings,
154
- message_retention_duration: Convert.number_to_duration(retention)
155
- end
156
-
157
- def update_topic topic_obj, *fields
158
- mask = Google::Protobuf::FieldMask.new paths: fields.map(&:to_s)
159
- publisher.update_topic topic: topic_obj, update_mask: mask
160
- end
161
-
162
- ##
163
- # Deletes the topic with the given name. All subscriptions to this topic
164
- # are also deleted. Raises GRPC status code 5 if the topic does not
165
- # exist. After a topic is deleted, a new topic may be created with the
166
- # same name.
167
- def delete_topic topic_name
168
- publisher.delete_topic topic: topic_path(topic_name)
169
- end
170
-
171
117
  ##
172
118
  # Adds one or more messages to the topic.
173
119
  # Raises GRPC status code 5 if the topic does not exist.
@@ -176,57 +122,11 @@ module Google
176
122
  def publish topic, messages, compress: false
177
123
  request = { topic: topic_path(topic), messages: messages }
178
124
  compress_options = ::Gapic::CallOptions.new metadata: { "grpc-internal-encoding-request": "gzip" }
179
- compress ? (publisher.publish request, compress_options) : (publisher.publish request)
180
- end
181
-
182
- ##
183
- # Gets the details of a subscription.
184
- def get_subscription subscription_name, options = {}
185
- subscriber.get_subscription subscription: subscription_path(subscription_name, options)
186
- end
187
-
188
- ##
189
- # Lists matching subscriptions by project and topic.
190
- def list_topics_subscriptions topic, options = {}
191
- publisher.list_topic_subscriptions topic: topic_path(topic, options),
192
- page_size: options[:max],
193
- page_token: options[:token]
194
- end
195
-
196
- ##
197
- # Lists matching subscriptions by project.
198
- def list_subscriptions options = {}
199
- paged_enum = subscriber.list_subscriptions project: project_path(options),
200
- page_size: options[:max],
201
- page_token: options[:token]
202
-
203
- paged_enum.response
204
- end
205
-
206
- ##
207
- # Creates a subscription on a given topic for a given subscriber.
208
- def create_subscription topic, subscription_name, options = {}
209
- updated_option = construct_create_subscription_options topic, subscription_name, options
210
- subscriber.create_subscription(**updated_option)
211
- end
212
-
213
- def update_subscription subscription_obj, *fields
214
- mask = Google::Protobuf::FieldMask.new paths: fields.map(&:to_s)
215
- subscriber.update_subscription subscription: subscription_obj, update_mask: mask
216
- end
217
-
218
- ##
219
- # Deletes an existing subscription. All pending messages in the subscription are immediately dropped.
220
- def delete_subscription subscription
221
- subscriber.delete_subscription subscription: subscription_path(subscription)
222
- end
223
-
224
- ##
225
- # Detaches a subscription from its topic. All messages retained in the subscription are dropped. Subsequent
226
- # `Pull` and `StreamingPull` requests will raise `FAILED_PRECONDITION`. If the subscription is a push
227
- # subscription, pushes to the endpoint will stop.
228
- def detach_subscription subscription
229
- publisher.detach_subscription subscription: subscription_path(subscription)
125
+ if compress
126
+ (topic_admin.publish_internal request, compress_options)
127
+ else
128
+ (topic_admin.publish_internal request)
129
+ end
230
130
  end
231
131
 
232
132
  ##
@@ -235,193 +135,36 @@ module Google
235
135
  max_messages = options.fetch(:max, 100).to_i
236
136
  return_immediately = !(!options.fetch(:immediate, true))
237
137
 
238
- subscriber.pull subscription: subscription_path(subscription, options),
239
- max_messages: max_messages,
240
- return_immediately: return_immediately
138
+ subscription_admin.pull_internal subscription: subscription_path(subscription, options),
139
+ max_messages: max_messages,
140
+ return_immediately: return_immediately
241
141
  end
242
142
 
243
143
  def streaming_pull request_enum, options = {}
244
- subscriber.streaming_pull request_enum, options
144
+ subscription_admin.streaming_pull_internal request_enum, options
245
145
  end
246
146
 
247
147
  ##
248
148
  # Acknowledges receipt of a message.
249
149
  def acknowledge subscription, *ack_ids
250
- subscriber.acknowledge subscription: subscription_path(subscription), ack_ids: ack_ids
251
- end
252
-
253
- ##
254
- # Modifies the PushConfig for a specified subscription.
255
- def modify_push_config subscription, endpoint, attributes
256
- # Convert attributes to strings to match the protobuf definition
257
- attributes = Hash[attributes.map { |k, v| [String(k), String(v)] }]
258
- push_config = Google::Cloud::PubSub::V1::PushConfig.new(
259
- push_endpoint: endpoint,
260
- attributes: attributes
261
- )
262
-
263
- subscriber.modify_push_config subscription: subscription_path(subscription),
264
- push_config: push_config
150
+ logger.log_ack_nack ack_ids, "ack"
151
+ subscription_admin.acknowledge_internal subscription: subscription_path(subscription),
152
+ ack_ids: ack_ids
265
153
  end
266
154
 
267
155
  ##
268
156
  # Modifies the ack deadline for a specific message.
269
157
  def modify_ack_deadline subscription, ids, deadline
270
- subscriber.modify_ack_deadline subscription: subscription_path(subscription),
271
- ack_ids: Array(ids),
272
- ack_deadline_seconds: deadline
273
- end
274
-
275
- ##
276
- # Lists snapshots by project.
277
- def list_snapshots options = {}
278
- paged_enum = subscriber.list_snapshots project: project_path(options),
279
- page_size: options[:max],
280
- page_token: options[:token]
281
-
282
- paged_enum.response
283
- end
284
-
285
- ##
286
- # Creates a snapshot on a given subscription.
287
- def create_snapshot subscription, snapshot_name, labels: nil
288
- subscriber.create_snapshot name: snapshot_path(snapshot_name),
289
- subscription: subscription_path(subscription),
290
- labels: labels
291
- end
292
-
293
- def update_snapshot snapshot_obj, *fields
294
- mask = Google::Protobuf::FieldMask.new paths: fields.map(&:to_s)
295
- subscriber.update_snapshot snapshot: snapshot_obj, update_mask: mask
296
- end
297
-
298
- ##
299
- # Deletes an existing snapshot.
300
- # All pending messages in the snapshot are immediately dropped.
301
- def delete_snapshot snapshot
302
- subscriber.delete_snapshot snapshot: snapshot_path(snapshot)
303
- end
304
-
305
- ##
306
- # Adjusts the given subscription to a time or snapshot.
307
- def seek subscription, time_or_snapshot
308
- if a_time? time_or_snapshot
309
- time = Convert.time_to_timestamp time_or_snapshot
310
- subscriber.seek subscription: subscription, time: time
311
- else
312
- time_or_snapshot = time_or_snapshot.name if time_or_snapshot.is_a? Snapshot
313
- subscriber.seek subscription: subscription_path(subscription),
314
- snapshot: snapshot_path(time_or_snapshot)
315
- end
316
- end
317
-
318
- ##
319
- # Lists schemas in the current (or given) project.
320
- # @param view [String, Symbol, nil] Possible values:
321
- # * `BASIC` - Include the name and type of the schema, but not the definition.
322
- # * `FULL` - Include all Schema object fields.
323
- #
324
- def list_schemas view, options = {}
325
- schema_view = Google::Cloud::PubSub::V1::SchemaView.const_get view.to_s.upcase
326
- paged_enum = schemas.list_schemas parent: project_path(options),
327
- view: schema_view,
328
- page_size: options[:max],
329
- page_token: options[:token]
330
-
331
- paged_enum.response
332
- end
333
-
334
- ##
335
- # Creates a schema in the current (or given) project.
336
- def create_schema schema_id, type, definition, options = {}
337
- schema = Google::Cloud::PubSub::V1::Schema.new(
338
- type: type,
339
- definition: definition
340
- )
341
- schemas.create_schema parent: project_path(options),
342
- schema: schema,
343
- schema_id: schema_id
344
- end
345
-
346
- ##
347
- # Gets the details of a schema.
348
- # @param view [String, Symbol, nil] The set of fields to return in the response. Possible values:
349
- # * `BASIC` - Include the name and type of the schema, but not the definition.
350
- # * `FULL` - Include all Schema object fields.
351
- #
352
- def get_schema schema_name, view, options = {}
353
- schema_view = Google::Cloud::PubSub::V1::SchemaView.const_get view.to_s.upcase
354
- schemas.get_schema name: schema_path(schema_name, options),
355
- view: schema_view
356
- end
357
-
358
- ##
359
- # Delete a schema.
360
- def delete_schema schema_name
361
- schemas.delete_schema name: schema_path(schema_name)
362
- end
363
-
364
- ##
365
- # Validate the definition string intended for a schema.
366
- def validate_schema type, definition, options = {}
367
- schema = Google::Cloud::PubSub::V1::Schema.new(
368
- type: type,
369
- definition: definition
370
- )
371
- schemas.validate_schema parent: project_path(options),
372
- schema: schema
373
- end
374
-
375
- ##
376
- # Validates a message against a schema.
377
- #
378
- # @param message_data [String] Message to validate against the provided `schema_spec`.
379
- # @param message_encoding [Google::Cloud::PubSub::V1::Encoding] The encoding expected for messages.
380
- # @param schema_name [String] Name of the schema against which to validate.
381
- # @param project [String] Name of the project if not the default project.
382
- # @param type [String] Ad-hoc schema type against which to validate.
383
- # @param definition [String] Ad-hoc schema definition against which to validate.
384
- #
385
- def validate_message message_data, message_encoding, schema_name: nil, project: nil, type: nil, definition: nil
386
- if type && definition
387
- schema = Google::Cloud::PubSub::V1::Schema.new(
388
- type: type,
389
- definition: definition
390
- )
158
+ if deadline.zero?
159
+ logger.log_ack_nack Array(ids), "nack"
391
160
  end
392
- schemas.validate_message parent: project_path(project: project),
393
- name: schema_path(schema_name),
394
- schema: schema,
395
- message: message_data,
396
- encoding: message_encoding
161
+ subscription_admin.modify_ack_deadline_internal subscription: subscription_path(subscription),
162
+ ack_ids: Array(ids),
163
+ ack_deadline_seconds: deadline
397
164
  end
398
165
 
399
166
  # Helper methods
400
167
 
401
- def get_topic_policy topic_name, options = {}
402
- iam.get_iam_policy resource: topic_path(topic_name, options)
403
- end
404
-
405
- def set_topic_policy topic_name, new_policy, options = {}
406
- iam.set_iam_policy resource: topic_path(topic_name, options), policy: new_policy
407
- end
408
-
409
- def test_topic_permissions topic_name, permissions, options = {}
410
- iam.test_iam_permissions resource: topic_path(topic_name, options), permissions: permissions
411
- end
412
-
413
- def get_subscription_policy subscription_name, options = {}
414
- iam.get_iam_policy resource: subscription_path(subscription_name, options)
415
- end
416
-
417
- def set_subscription_policy subscription_name, new_policy, options = {}
418
- iam.set_iam_policy resource: subscription_path(subscription_name, options), policy: new_policy
419
- end
420
-
421
- def test_subscription_permissions subscription_name, permissions, options = {}
422
- iam.test_iam_permissions resource: subscription_path(subscription_name, options), permissions: permissions
423
- end
424
-
425
168
  def project_path options = {}
426
169
  project_name = options[:project] || project
427
170
  "projects/#{project_name}"
@@ -447,10 +190,6 @@ module Google
447
190
  "#{project_path options}/schemas/#{schema_name}"
448
191
  end
449
192
 
450
- def inspect
451
- "#<#{self.class.name} (#{@project})>"
452
- end
453
-
454
193
  protected
455
194
 
456
195
  # Set the timeout in the client config.
@@ -465,48 +204,8 @@ module Google
465
204
  end
466
205
  end
467
206
 
468
- def a_time? obj
469
- return false unless obj.respond_to? :to_time
470
- # Rails' String#to_time returns nil if the string doesn't parse.
471
- return false if obj.to_time.nil?
472
- true
473
- end
474
-
475
- def dead_letter_policy options
476
- return nil unless options[:dead_letter_topic_name]
477
- policy = Google::Cloud::PubSub::V1::DeadLetterPolicy.new dead_letter_topic: options[:dead_letter_topic_name]
478
- if options[:dead_letter_max_delivery_attempts]
479
- policy.max_delivery_attempts = options[:dead_letter_max_delivery_attempts]
480
- end
481
- policy
482
- end
483
-
484
- private
485
-
486
- def construct_create_subscription_options topic, subscription_name, options
487
- excess_options = [:deadline,
488
- :retention,
489
- :retain_acked,
490
- :message_ordering,
491
- :endpoint,
492
- :dead_letter_topic_name,
493
- :dead_letter_max_delivery_attempts,
494
- :dead_letter_topic]
495
-
496
- new_options = options.filter { |k, v| !v.nil? && !excess_options.include?(k) }
497
- new_options[:name] = subscription_path subscription_name, options
498
- new_options[:topic] = topic_path topic
499
- new_options[:message_retention_duration] = Convert.number_to_duration options[:retention]
500
- new_options[:dead_letter_policy] = dead_letter_policy options
501
- new_options[:ack_deadline_seconds] = options[:deadline]
502
- new_options[:retain_acked_messages] = options[:retain_acked]
503
- new_options[:enable_message_ordering] = options[:message_ordering]
504
-
505
- new_options.compact
506
- end
507
207
  end
508
208
  end
509
-
510
209
  Pubsub = PubSub unless const_defined? :Pubsub
511
210
  end
512
211
  end