google-cloud-pubsub 2.4.0 → 2.7.1
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 +4 -4
- data/AUTHENTICATION.md +2 -1
- data/CHANGELOG.md +55 -0
- data/CONTRIBUTING.md +2 -3
- data/OVERVIEW.md +9 -6
- data/lib/google/cloud/pubsub.rb +0 -4
- data/lib/google/cloud/pubsub/async_publisher.rb +42 -6
- data/lib/google/cloud/pubsub/async_publisher/batch.rb +2 -6
- data/lib/google/cloud/pubsub/batch_publisher.rb +31 -30
- data/lib/google/cloud/pubsub/errors.rb +8 -0
- data/lib/google/cloud/pubsub/flow_controller.rb +139 -0
- data/lib/google/cloud/pubsub/project.rb +248 -11
- data/lib/google/cloud/pubsub/schema.rb +310 -0
- data/lib/google/cloud/pubsub/schema/list.rb +180 -0
- data/lib/google/cloud/pubsub/service.rb +143 -31
- data/lib/google/cloud/pubsub/snapshot.rb +1 -0
- data/lib/google/cloud/pubsub/subscriber.rb +22 -22
- data/lib/google/cloud/pubsub/subscription.rb +27 -25
- data/lib/google/cloud/pubsub/topic.rb +103 -3
- data/lib/google/cloud/pubsub/version.rb +1 -1
- metadata +20 -3
@@ -0,0 +1,139 @@
|
|
1
|
+
# Copyright 2021 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 "google/cloud/pubsub/errors"
|
17
|
+
require "concurrent/atomics"
|
18
|
+
|
19
|
+
module Google
|
20
|
+
module Cloud
|
21
|
+
module PubSub
|
22
|
+
##
|
23
|
+
# @private
|
24
|
+
#
|
25
|
+
# Used to control the flow of messages passing through it.
|
26
|
+
#
|
27
|
+
class FlowController
|
28
|
+
attr_reader :message_limit
|
29
|
+
attr_reader :byte_limit
|
30
|
+
attr_reader :limit_exceeded_behavior
|
31
|
+
##
|
32
|
+
# @private Implementation accessors
|
33
|
+
attr_reader :outstanding_messages, :outstanding_bytes, :awaiting
|
34
|
+
|
35
|
+
def initialize message_limit: 1000, byte_limit: 10_000_000, limit_exceeded_behavior: :ignore
|
36
|
+
unless [:ignore, :error, :block].include? limit_exceeded_behavior
|
37
|
+
raise ArgumentError, "limit_exceeded_behavior must be one of :ignore, :error, :block"
|
38
|
+
end
|
39
|
+
if [:error, :block].include?(limit_exceeded_behavior) && message_limit < 1
|
40
|
+
raise ArgumentError,
|
41
|
+
"Flow control message limit (#{message_limit}) exceeded by a single message, would block forever"
|
42
|
+
end
|
43
|
+
@mutex = Mutex.new
|
44
|
+
@message_limit = message_limit
|
45
|
+
@byte_limit = byte_limit
|
46
|
+
@limit_exceeded_behavior = limit_exceeded_behavior
|
47
|
+
@outstanding_messages = 0
|
48
|
+
@outstanding_bytes = 0
|
49
|
+
|
50
|
+
@awaiting = []
|
51
|
+
end
|
52
|
+
|
53
|
+
def acquire message_size
|
54
|
+
return if limit_exceeded_behavior == :ignore
|
55
|
+
@mutex.lock
|
56
|
+
if limit_exceeded_behavior == :error && would_exceed_message_limit?
|
57
|
+
raise FlowControlLimitError, "Flow control message limit (#{message_limit}) would be exceeded"
|
58
|
+
end
|
59
|
+
if limit_exceeded_behavior == :error && would_exceed_byte_limit?(message_size)
|
60
|
+
raise FlowControlLimitError,
|
61
|
+
"Flow control byte limit (#{byte_limit}) would be exceeded, message_size: #{message_size}"
|
62
|
+
end
|
63
|
+
if limit_exceeded_behavior == :block && message_size > byte_limit
|
64
|
+
raise FlowControlLimitError,
|
65
|
+
"Flow control byte limit (#{byte_limit}) exceeded by a single message, would block forever"
|
66
|
+
end
|
67
|
+
|
68
|
+
acquire_or_wait message_size
|
69
|
+
ensure
|
70
|
+
@mutex.unlock if @mutex.owned?
|
71
|
+
end
|
72
|
+
|
73
|
+
def release message_size
|
74
|
+
return if limit_exceeded_behavior == :ignore
|
75
|
+
@mutex.synchronize do
|
76
|
+
raise "Flow control messages count would be negative" if (@outstanding_messages - 1).negative?
|
77
|
+
raise "Flow control bytes count would be negative" if (@outstanding_bytes - message_size).negative?
|
78
|
+
|
79
|
+
@outstanding_messages -= 1
|
80
|
+
@outstanding_bytes -= message_size
|
81
|
+
@awaiting.first.set unless @awaiting.empty?
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
protected
|
86
|
+
|
87
|
+
# rubocop:disable Style/IdenticalConditionalBranches
|
88
|
+
# rubocop:disable Style/GuardClause
|
89
|
+
|
90
|
+
def acquire_or_wait message_size
|
91
|
+
waiter = nil
|
92
|
+
while is_new_and_others_wait?(waiter) ||
|
93
|
+
would_exceed_byte_limit?(message_size) ||
|
94
|
+
would_exceed_message_limit?
|
95
|
+
|
96
|
+
if waiter.nil?
|
97
|
+
waiter = Concurrent::Event.new
|
98
|
+
# This waiter gets added to the back of the line.
|
99
|
+
@awaiting << waiter
|
100
|
+
else
|
101
|
+
waiter = Concurrent::Event.new
|
102
|
+
# This waiter already in line stays at the head of the line.
|
103
|
+
@awaiting[0] = waiter
|
104
|
+
end
|
105
|
+
@mutex.unlock
|
106
|
+
waiter.wait
|
107
|
+
@mutex.lock
|
108
|
+
end
|
109
|
+
@outstanding_messages += 1
|
110
|
+
@outstanding_bytes += message_size
|
111
|
+
|
112
|
+
@awaiting.shift if waiter # Remove the newly released waiter from the head of the queue.
|
113
|
+
|
114
|
+
# There may be some surplus left; let the next message waiting try to acquire a permit.
|
115
|
+
if !@awaiting.empty? && @outstanding_bytes < byte_limit && @outstanding_messages < message_limit
|
116
|
+
@awaiting.first.set
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# rubocop:enable Style/IdenticalConditionalBranches
|
121
|
+
# rubocop:enable Style/GuardClause
|
122
|
+
|
123
|
+
def is_new_and_others_wait? waiter
|
124
|
+
waiter.nil? && !@awaiting.empty?
|
125
|
+
end
|
126
|
+
|
127
|
+
def would_exceed_message_limit?
|
128
|
+
@outstanding_messages + 1 > message_limit
|
129
|
+
end
|
130
|
+
|
131
|
+
def would_exceed_byte_limit? bytes_requested
|
132
|
+
@outstanding_bytes + bytes_requested > byte_limit
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
Pubsub = PubSub unless const_defined? :Pubsub
|
138
|
+
end
|
139
|
+
end
|
@@ -18,6 +18,7 @@ require "google/cloud/pubsub/service"
|
|
18
18
|
require "google/cloud/pubsub/credentials"
|
19
19
|
require "google/cloud/pubsub/topic"
|
20
20
|
require "google/cloud/pubsub/batch_publisher"
|
21
|
+
require "google/cloud/pubsub/schema"
|
21
22
|
require "google/cloud/pubsub/snapshot"
|
22
23
|
|
23
24
|
module Google
|
@@ -102,6 +103,16 @@ module Google
|
|
102
103
|
# * `:threads` (Hash) The number of threads to create to handle concurrent calls by the publisher:
|
103
104
|
# * `:publish` (Integer) The number of threads used to publish messages. Default is 2.
|
104
105
|
# * `:callback` (Integer) The number of threads to handle the published messages' callbacks. Default is 4.
|
106
|
+
# * `:flow_control` (Hash) The client flow control settings for message publishing:
|
107
|
+
# * `:message_limit` (Integer) The maximum number of messages allowed to wait to be published. Default is
|
108
|
+
# `10 * max_messages`.
|
109
|
+
# * `:byte_limit` (Integer) The maximum total size of messages allowed to wait to be published. Default is
|
110
|
+
# `10 * max_bytes`.
|
111
|
+
# * `:limit_exceeded_behavior` (Symbol) The action to take when publish flow control limits are exceeded.
|
112
|
+
# Possible values include: `:ignore` - Flow control is disabled. `:error` - Calls to {Topic#publish_async}
|
113
|
+
# will raise {FlowControlLimitError} when publish flow control limits are exceeded. `:block` - Calls to
|
114
|
+
# {Topic#publish_async} will block until capacity is available when publish flow control limits are
|
115
|
+
# exceeded. The default value is `:ignore`.
|
105
116
|
#
|
106
117
|
# @return [Google::Cloud::PubSub::Topic, nil] Returns `nil` if topic
|
107
118
|
# does not exist.
|
@@ -192,15 +203,41 @@ module Google
|
|
192
203
|
#
|
193
204
|
# Hash keys and values may include the following:
|
194
205
|
#
|
195
|
-
# * `:max_bytes` (Integer) The maximum size of messages to be collected
|
196
|
-
# is 1,000,000 (1MB).
|
197
|
-
# * `:max_messages` (Integer) The maximum number of messages to be
|
198
|
-
# Default is 100.
|
199
|
-
# * `:interval` (Numeric) The number of seconds to collect messages before
|
200
|
-
# 0.01.
|
201
|
-
# * `:threads` (Hash) The number of threads to create to handle concurrent
|
202
|
-
#
|
203
|
-
#
|
206
|
+
# * `:max_bytes` (Integer) The maximum size of messages to be collected
|
207
|
+
# before the batch is published. Default is 1,000,000 (1MB).
|
208
|
+
# * `:max_messages` (Integer) The maximum number of messages to be
|
209
|
+
# collected before the batch is published. Default is 100.
|
210
|
+
# * `:interval` (Numeric) The number of seconds to collect messages before
|
211
|
+
# the batch is published. Default is 0.01.
|
212
|
+
# * `:threads` (Hash) The number of threads to create to handle concurrent
|
213
|
+
# calls by the publisher:
|
214
|
+
#
|
215
|
+
# * `:publish` (Integer) The number of threads used to publish messages.
|
216
|
+
# Default is 2.
|
217
|
+
# * `:callback` (Integer) The number of threads to handle the published
|
218
|
+
# messages' callbacks. Default is 4.
|
219
|
+
# * `:flow_control` (Hash) The client flow control settings for message publishing:
|
220
|
+
# * `:message_limit` (Integer) The maximum number of messages allowed to wait to be published. Default is
|
221
|
+
# `10 * max_messages`.
|
222
|
+
# * `:byte_limit` (Integer) The maximum total size of messages allowed to wait to be published. Default is
|
223
|
+
# `10 * max_bytes`.
|
224
|
+
# * `:limit_exceeded_behavior` (Symbol) The action to take when publish flow control limits are exceeded.
|
225
|
+
# Possible values include: `:ignore` - Flow control is disabled. `:error` - Calls to {Topic#publish_async}
|
226
|
+
# will raise {FlowControlLimitError} when publish flow control limits are exceeded. `:block` - Calls to
|
227
|
+
# {Topic#publish_async} will block until capacity is available when publish flow control limits are
|
228
|
+
# exceeded. The default value is `:ignore`.
|
229
|
+
# @param [String] schema_name The name of the schema that messages
|
230
|
+
# published should be validated against. Optional. The value can be a
|
231
|
+
# simple schema ID (relative name), in which case the current project
|
232
|
+
# ID will be supplied, or a fully-qualified schema name in the form
|
233
|
+
# `projects/{project_id}/schemas/{schema_id}`. If provided,
|
234
|
+
# `message_encoding` must also be provided.
|
235
|
+
# @param [String, Symbol] message_encoding The encoding of messages validated
|
236
|
+
# against the schema identified by `schema_name`. Optional. Values include:
|
237
|
+
#
|
238
|
+
# * `JSON` - JSON encoding.
|
239
|
+
# * `BINARY` - Binary encoding, as defined by the schema type. For some
|
240
|
+
# schema types, binary encoding may not be available.
|
204
241
|
#
|
205
242
|
# @return [Google::Cloud::PubSub::Topic]
|
206
243
|
#
|
@@ -210,12 +247,20 @@ module Google
|
|
210
247
|
# pubsub = Google::Cloud::PubSub.new
|
211
248
|
# topic = pubsub.create_topic "my-topic"
|
212
249
|
#
|
213
|
-
def create_topic topic_name,
|
250
|
+
def create_topic topic_name,
|
251
|
+
labels: nil,
|
252
|
+
kms_key: nil,
|
253
|
+
persistence_regions: nil,
|
254
|
+
async: nil,
|
255
|
+
schema_name: nil,
|
256
|
+
message_encoding: nil
|
214
257
|
ensure_service!
|
215
258
|
grpc = service.create_topic topic_name,
|
216
259
|
labels: labels,
|
217
260
|
kms_key_name: kms_key,
|
218
|
-
persistence_regions: persistence_regions
|
261
|
+
persistence_regions: persistence_regions,
|
262
|
+
schema_name: schema_name,
|
263
|
+
message_encoding: message_encoding
|
219
264
|
Topic.from_grpc grpc, service, async: async
|
220
265
|
end
|
221
266
|
alias new_topic create_topic
|
@@ -387,6 +432,198 @@ module Google
|
|
387
432
|
alias find_snapshots snapshots
|
388
433
|
alias list_snapshots snapshots
|
389
434
|
|
435
|
+
##
|
436
|
+
# Retrieves schema by name.
|
437
|
+
#
|
438
|
+
# @param [String] schema_name Name of a schema. The value can
|
439
|
+
# be a simple schema ID, in which case the current project ID
|
440
|
+
# will be supplied, or a fully-qualified schema name in the form
|
441
|
+
# `projects/{project_id}/schemas/{schema_id}`.
|
442
|
+
# @param view [Symbol, String, nil] Possible values:
|
443
|
+
# * `BASIC` - Include the `name` and `type` of the schema, but not the `definition`.
|
444
|
+
# * `FULL` - Include all Schema object fields.
|
445
|
+
#
|
446
|
+
# The default value is `FULL`.
|
447
|
+
# @param [String] project If the schema belongs to a project other
|
448
|
+
# than the one currently connected to, the alternate project ID can be
|
449
|
+
# specified here. Not used if a fully-qualified schema name is
|
450
|
+
# provided for `schema_name`.
|
451
|
+
# @param [Boolean] skip_lookup Optionally create a {Schema} object
|
452
|
+
# without verifying the schema resource exists on the Pub/Sub
|
453
|
+
# service. Calls made on this object will raise errors if the service
|
454
|
+
# resource does not exist. Default is `false`.
|
455
|
+
#
|
456
|
+
# @return [Google::Cloud::PubSub::Schema, nil] Returns `nil` if
|
457
|
+
# the schema does not exist.
|
458
|
+
#
|
459
|
+
# @example
|
460
|
+
# require "google/cloud/pubsub"
|
461
|
+
#
|
462
|
+
# pubsub = Google::Cloud::PubSub.new
|
463
|
+
#
|
464
|
+
# schema = pubsub.schema "my-schema"
|
465
|
+
# schema.name #=> "projects/my-project/schemas/my-schema"
|
466
|
+
# schema.type #=> :PROTOCOL_BUFFER
|
467
|
+
# schema.definition # The schema definition
|
468
|
+
#
|
469
|
+
# @example Skip the lookup against the service with `skip_lookup`:
|
470
|
+
# require "google/cloud/pubsub"
|
471
|
+
#
|
472
|
+
# pubsub = Google::Cloud::PubSub.new
|
473
|
+
#
|
474
|
+
# # No API call is made to retrieve the schema information.
|
475
|
+
# # The default project is used in the name.
|
476
|
+
# schema = pubsub.schema "my-schema", skip_lookup: true
|
477
|
+
# schema.name #=> "projects/my-project/schemas/my-schema"
|
478
|
+
# schema.type #=> nil
|
479
|
+
# schema.definition #=> nil
|
480
|
+
#
|
481
|
+
# @example Omit the schema definition with `view: :basic`:
|
482
|
+
# require "google/cloud/pubsub"
|
483
|
+
#
|
484
|
+
# pubsub = Google::Cloud::PubSub.new
|
485
|
+
#
|
486
|
+
# schema = pubsub.schema "my-schema", view: :basic
|
487
|
+
# schema.name #=> "projects/my-project/schemas/my-schema"
|
488
|
+
# schema.type #=> :PROTOCOL_BUFFER
|
489
|
+
# schema.definition #=> nil
|
490
|
+
#
|
491
|
+
def schema schema_name, view: nil, project: nil, skip_lookup: nil
|
492
|
+
ensure_service!
|
493
|
+
options = { project: project }
|
494
|
+
return Schema.from_name schema_name, view, service, options if skip_lookup
|
495
|
+
view ||= :FULL
|
496
|
+
grpc = service.get_schema schema_name, view, options
|
497
|
+
Schema.from_grpc grpc, service
|
498
|
+
rescue Google::Cloud::NotFoundError
|
499
|
+
nil
|
500
|
+
end
|
501
|
+
alias get_schema schema
|
502
|
+
alias find_schema schema
|
503
|
+
|
504
|
+
##
|
505
|
+
# Creates a new schema.
|
506
|
+
#
|
507
|
+
# @param [String] schema_id The ID to use for the schema, which will
|
508
|
+
# become the final component of the schema's resource name. Required.
|
509
|
+
#
|
510
|
+
# The schema ID (relative name) must start with a letter, and
|
511
|
+
# contain only letters (`[A-Za-z]`), numbers (`[0-9]`), dashes (`-`),
|
512
|
+
# underscores (`_`), periods (`.`), tildes (`~`), plus (`+`) or percent
|
513
|
+
# signs (`%`). It must be between 3 and 255 characters in length, and
|
514
|
+
# it must not start with `goog`.
|
515
|
+
# @param [String, Symbol] type The type of the schema. Required. Possible
|
516
|
+
# values are case-insensitive and include:
|
517
|
+
#
|
518
|
+
# * `PROTOCOL_BUFFER` - A Protocol Buffer schema definition.
|
519
|
+
# * `AVRO` - An Avro schema definition.
|
520
|
+
# @param [String] definition The definition of the schema. Required. This
|
521
|
+
# should be a string representing the full definition of the schema that
|
522
|
+
# is a valid schema definition of the type specified in `type`.
|
523
|
+
# @param [String] project If the schema belongs to a project other
|
524
|
+
# than the one currently connected to, the alternate project ID can be
|
525
|
+
# specified here. Optional.
|
526
|
+
#
|
527
|
+
# @return [Google::Cloud::PubSub::Schema]
|
528
|
+
#
|
529
|
+
# @example
|
530
|
+
# require "google/cloud/pubsub"
|
531
|
+
#
|
532
|
+
# pubsub = Google::Cloud::PubSub.new
|
533
|
+
#
|
534
|
+
# definition = "..."
|
535
|
+
# schema = pubsub.create_schema "my-schema", :avro, definition
|
536
|
+
# schema.name #=> "projects/my-project/schemas/my-schema"
|
537
|
+
#
|
538
|
+
def create_schema schema_id, type, definition, project: nil
|
539
|
+
ensure_service!
|
540
|
+
type = type.to_s.upcase
|
541
|
+
grpc = service.create_schema schema_id, type, definition, project: project
|
542
|
+
Schema.from_grpc grpc, service
|
543
|
+
end
|
544
|
+
alias new_schema create_schema
|
545
|
+
|
546
|
+
##
|
547
|
+
# Retrieves a list of schemas for the given project.
|
548
|
+
#
|
549
|
+
# @param view [String, Symbol, nil] The set of fields to return in the response. Possible values:
|
550
|
+
#
|
551
|
+
# * `BASIC` - Include the `name` and `type` of the schema, but not the `definition`.
|
552
|
+
# * `FULL` - Include all Schema object fields.
|
553
|
+
#
|
554
|
+
# The default value is `FULL`.
|
555
|
+
# @param [String] token A previously-returned page token representing
|
556
|
+
# part of the larger set of results to view.
|
557
|
+
# @param [Integer] max Maximum number of schemas to return.
|
558
|
+
#
|
559
|
+
# @return [Array<Google::Cloud::PubSub::Schema>] (See
|
560
|
+
# {Google::Cloud::PubSub::Schema::List})
|
561
|
+
#
|
562
|
+
# @example
|
563
|
+
# require "google/cloud/pubsub"
|
564
|
+
#
|
565
|
+
# pubsub = Google::Cloud::PubSub.new
|
566
|
+
#
|
567
|
+
# schemas = pubsub.schemas
|
568
|
+
# schemas.each do |schema|
|
569
|
+
# puts schema.name
|
570
|
+
# end
|
571
|
+
#
|
572
|
+
# @example Retrieve all schemas: (See {Schema::List#all})
|
573
|
+
# require "google/cloud/pubsub"
|
574
|
+
#
|
575
|
+
# pubsub = Google::Cloud::PubSub.new
|
576
|
+
#
|
577
|
+
# schemas = pubsub.schemas
|
578
|
+
# schemas.all do |schema|
|
579
|
+
# puts schema.name
|
580
|
+
# end
|
581
|
+
#
|
582
|
+
def schemas view: nil, token: nil, max: nil
|
583
|
+
ensure_service!
|
584
|
+
view ||= :FULL
|
585
|
+
options = { token: token, max: max }
|
586
|
+
grpc = service.list_schemas view, options
|
587
|
+
Schema::List.from_grpc grpc, service, view, max
|
588
|
+
end
|
589
|
+
alias find_schemas schemas
|
590
|
+
alias list_schemas schemas
|
591
|
+
|
592
|
+
##
|
593
|
+
# Validates a schema type and definition.
|
594
|
+
#
|
595
|
+
# @param [String, Symbol] type The type of the schema. Required. Possible
|
596
|
+
# values are case-insensitive and include:
|
597
|
+
#
|
598
|
+
# * `PROTOCOL_BUFFER` - A Protocol Buffer schema definition.
|
599
|
+
# * `AVRO` - An Avro schema definition.
|
600
|
+
# @param [String] definition The definition of the schema. Required. This
|
601
|
+
# should be a string representing the full definition of the schema that
|
602
|
+
# is a valid schema definition of the type specified in `type`.
|
603
|
+
# @param [String] project If the schema belongs to a project other
|
604
|
+
# than the one currently connected to, the alternate project ID can be
|
605
|
+
# specified here. Optional.
|
606
|
+
#
|
607
|
+
# @return [Boolean] `true` if the schema is valid, `false` otherwise.
|
608
|
+
#
|
609
|
+
# @example
|
610
|
+
# require "google/cloud/pubsub"
|
611
|
+
#
|
612
|
+
# pubsub = Google::Cloud::PubSub.new
|
613
|
+
#
|
614
|
+
# definition = "..."
|
615
|
+
# pubsub.validate_schema :avro, definition #=> true
|
616
|
+
#
|
617
|
+
def valid_schema? type, definition, project: nil
|
618
|
+
ensure_service!
|
619
|
+
type = type.to_s.upcase
|
620
|
+
service.validate_schema type, definition, project: project # return type is empty
|
621
|
+
true
|
622
|
+
rescue Google::Cloud::InvalidArgumentError
|
623
|
+
false
|
624
|
+
end
|
625
|
+
alias validate_schema valid_schema?
|
626
|
+
|
390
627
|
protected
|
391
628
|
|
392
629
|
##
|
@@ -0,0 +1,310 @@
|
|
1
|
+
# Copyright 2021 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 "google/cloud/pubsub/schema/list"
|
17
|
+
require "google/cloud/pubsub/v1"
|
18
|
+
|
19
|
+
module Google
|
20
|
+
module Cloud
|
21
|
+
module PubSub
|
22
|
+
##
|
23
|
+
# # Schema
|
24
|
+
#
|
25
|
+
# A schema resource.
|
26
|
+
#
|
27
|
+
# @example
|
28
|
+
# require "google/cloud/pubsub"
|
29
|
+
#
|
30
|
+
# pubsub = Google::Cloud::PubSub.new
|
31
|
+
#
|
32
|
+
# schema = pubsub.schema "my-schema"
|
33
|
+
# schema.name #=> "projects/my-project/schemas/my-schema"
|
34
|
+
# schema.type #=> :PROTOCOL_BUFFER
|
35
|
+
#
|
36
|
+
class Schema
|
37
|
+
##
|
38
|
+
# @private The Service object.
|
39
|
+
attr_accessor :service
|
40
|
+
|
41
|
+
##
|
42
|
+
# @private The gRPC Google::Cloud::PubSub::V1::Schema object.
|
43
|
+
attr_accessor :grpc
|
44
|
+
|
45
|
+
##
|
46
|
+
# @private Create a new Schema instance.
|
47
|
+
def initialize grpc, service, view: nil
|
48
|
+
@grpc = grpc
|
49
|
+
@service = service
|
50
|
+
@exists = nil
|
51
|
+
@view = view || :FULL
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# The name of the schema.
|
56
|
+
#
|
57
|
+
# @return [String] A fully-qualified schema name in the form `projects/{project_id}/schemas/{schema_id}`.
|
58
|
+
#
|
59
|
+
def name
|
60
|
+
@grpc.name
|
61
|
+
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# The type of the schema. Possible values include:
|
65
|
+
#
|
66
|
+
# * `PROTOCOL_BUFFER` - A Protocol Buffer schema definition.
|
67
|
+
# * `AVRO` - An Avro schema definition.
|
68
|
+
#
|
69
|
+
# @return [String, nil] The upper-case type name.
|
70
|
+
#
|
71
|
+
def type
|
72
|
+
return nil if reference?
|
73
|
+
@grpc.type
|
74
|
+
end
|
75
|
+
|
76
|
+
##
|
77
|
+
# The definition of the schema. This should be a string representing the full definition of the schema that is a
|
78
|
+
# valid schema definition of the type specified in {#type}.
|
79
|
+
#
|
80
|
+
# @return [String, nil] The schema definition.
|
81
|
+
#
|
82
|
+
def definition
|
83
|
+
return nil if reference?
|
84
|
+
@grpc.definition if @grpc.definition && !@grpc.definition.empty?
|
85
|
+
end
|
86
|
+
|
87
|
+
##
|
88
|
+
# Validates a message against a schema.
|
89
|
+
#
|
90
|
+
# @param message_data [String] Message to validate against the provided `schema_spec`.
|
91
|
+
# @param message_encoding [Symbol, String] The encoding of the message validated against the schema. Values
|
92
|
+
# include:
|
93
|
+
#
|
94
|
+
# * `JSON` - JSON encoding.
|
95
|
+
# * `BINARY` - Binary encoding, as defined by the schema type. For some schema types, binary encoding may not
|
96
|
+
# be available.
|
97
|
+
#
|
98
|
+
# @return [Boolean] Returns `true` if the message validiation succeeds, `false` otherwise.
|
99
|
+
#
|
100
|
+
# @example
|
101
|
+
# require "google/cloud/pubsub"
|
102
|
+
#
|
103
|
+
# pubsub = Google::Cloud::PubSub.new
|
104
|
+
# schema = pubsub.schema "my-schema"
|
105
|
+
#
|
106
|
+
# message_data = { "name" => "Alaska", "post_abbr" => "AK" }.to_json
|
107
|
+
# schema.validate_message message_data, :json
|
108
|
+
#
|
109
|
+
def validate_message message_data, message_encoding
|
110
|
+
message_encoding = message_encoding.to_s.upcase
|
111
|
+
service.validate_message message_data, message_encoding, schema_name: name
|
112
|
+
true
|
113
|
+
rescue Google::Cloud::InvalidArgumentError
|
114
|
+
false
|
115
|
+
end
|
116
|
+
|
117
|
+
##
|
118
|
+
# Removes the schema, if it exists.
|
119
|
+
#
|
120
|
+
# @return [Boolean] Returns `true` if the schema was deleted.
|
121
|
+
#
|
122
|
+
# @example
|
123
|
+
# require "google/cloud/pubsub"
|
124
|
+
#
|
125
|
+
# pubsub = Google::Cloud::PubSub.new
|
126
|
+
# schema = pubsub.schema "my-schema"
|
127
|
+
#
|
128
|
+
# schema.delete
|
129
|
+
#
|
130
|
+
def delete
|
131
|
+
ensure_service!
|
132
|
+
service.delete_schema name
|
133
|
+
true
|
134
|
+
end
|
135
|
+
|
136
|
+
##
|
137
|
+
# Reloads the schema with current data from the Pub/Sub service.
|
138
|
+
#
|
139
|
+
# @param view [Symbol, String, nil] The set of fields to return in the response. Possible values:
|
140
|
+
# * `BASIC` - Include the `name` and `type` of the schema, but not the `definition`.
|
141
|
+
# * `FULL` - Include all Schema object fields.
|
142
|
+
#
|
143
|
+
# Optional. If not provided or `nil`, the last non-nil `view` argument to this method will be used if one has
|
144
|
+
# been given, othewise `FULL` will be used.
|
145
|
+
#
|
146
|
+
# @return [Google::Cloud::PubSub::Schema] Returns the reloaded schema.
|
147
|
+
#
|
148
|
+
# @example Skip retrieving the schema from the service, then load it:
|
149
|
+
# require "google/cloud/pubsub"
|
150
|
+
#
|
151
|
+
# pubsub = Google::Cloud::PubSub.new
|
152
|
+
# schema = pubsub.schema "my-schema", skip_lookup: true
|
153
|
+
#
|
154
|
+
# schema.reload!
|
155
|
+
#
|
156
|
+
# @example Use the `view` option to load the basic or full resource:
|
157
|
+
# require "google/cloud/pubsub"
|
158
|
+
#
|
159
|
+
# pubsub = Google::Cloud::PubSub.new
|
160
|
+
# schema = pubsub.schema "my-schema", view: :basic
|
161
|
+
# schema.resource_partial? #=> true
|
162
|
+
#
|
163
|
+
# schema.reload! view: :full
|
164
|
+
# schema.resource_partial? #=> false
|
165
|
+
#
|
166
|
+
# @!group Lifecycle
|
167
|
+
#
|
168
|
+
def reload! view: nil
|
169
|
+
ensure_service!
|
170
|
+
@view = view || @view
|
171
|
+
@grpc = service.get_schema name, @view
|
172
|
+
@reference = nil
|
173
|
+
@exists = nil
|
174
|
+
self
|
175
|
+
end
|
176
|
+
alias refresh! reload!
|
177
|
+
|
178
|
+
##
|
179
|
+
# Determines whether the schema exists in the Pub/Sub service.
|
180
|
+
#
|
181
|
+
# @example
|
182
|
+
# require "google/cloud/pubsub"
|
183
|
+
#
|
184
|
+
# pubsub = Google::Cloud::PubSub.new
|
185
|
+
#
|
186
|
+
# schema = pubsub.schema "my-schema"
|
187
|
+
# schema.exists? #=> true
|
188
|
+
#
|
189
|
+
def exists?
|
190
|
+
# Always true if the object is not set as reference
|
191
|
+
return true unless reference?
|
192
|
+
# If we have a value, return it
|
193
|
+
return @exists unless @exists.nil?
|
194
|
+
ensure_grpc!
|
195
|
+
@exists = true
|
196
|
+
rescue Google::Cloud::NotFoundError
|
197
|
+
@exists = false
|
198
|
+
end
|
199
|
+
|
200
|
+
##
|
201
|
+
# Determines whether the schema object was created without retrieving the
|
202
|
+
# resource representation from the Pub/Sub service.
|
203
|
+
#
|
204
|
+
# @return [Boolean] `true` when the schema was created without a resource
|
205
|
+
# representation, `false` otherwise.
|
206
|
+
#
|
207
|
+
# @example
|
208
|
+
# require "google/cloud/pubsub"
|
209
|
+
#
|
210
|
+
# pubsub = Google::Cloud::PubSub.new
|
211
|
+
#
|
212
|
+
# schema = pubsub.schema "my-schema", skip_lookup: true
|
213
|
+
# schema.reference? #=> true
|
214
|
+
#
|
215
|
+
def reference?
|
216
|
+
@grpc.type.nil? || @grpc.type == :TYPE_UNSPECIFIED
|
217
|
+
end
|
218
|
+
|
219
|
+
##
|
220
|
+
# Determines whether the schema object was created with a resource
|
221
|
+
# representation from the Pub/Sub service.
|
222
|
+
#
|
223
|
+
# @return [Boolean] `true` when the schema was created with a resource
|
224
|
+
# representation, `false` otherwise.
|
225
|
+
#
|
226
|
+
# @example
|
227
|
+
# require "google/cloud/pubsub"
|
228
|
+
#
|
229
|
+
# pubsub = Google::Cloud::PubSub.new
|
230
|
+
#
|
231
|
+
# schema = pubsub.schema "my-schema"
|
232
|
+
# schema.resource? #=> true
|
233
|
+
#
|
234
|
+
def resource?
|
235
|
+
!reference?
|
236
|
+
end
|
237
|
+
|
238
|
+
##
|
239
|
+
# Whether the schema was created with a partial resource representation
|
240
|
+
# from the Pub/Sub service.
|
241
|
+
#
|
242
|
+
# @return [Boolean] `true` when the schema was created with a partial
|
243
|
+
# resource representation, `false` otherwise.
|
244
|
+
#
|
245
|
+
# @example
|
246
|
+
# require "google/cloud/pubsub"
|
247
|
+
#
|
248
|
+
# pubsub = Google::Cloud::PubSub.new
|
249
|
+
# schema = pubsub.schema "my-schema", view: :basic
|
250
|
+
#
|
251
|
+
# schema.resource_partial? #=> true
|
252
|
+
# schema.reload! view: :full # Loads the full resource.
|
253
|
+
# schema.resource_partial? #=> false
|
254
|
+
#
|
255
|
+
def resource_partial?
|
256
|
+
resource? && !resource_full?
|
257
|
+
end
|
258
|
+
|
259
|
+
##
|
260
|
+
# Whether the schema was created with a full resource representation
|
261
|
+
# from the Pub/Sub service.
|
262
|
+
#
|
263
|
+
# @return [Boolean] `true` when the schema was created with a full
|
264
|
+
# resource representation, `false` otherwise.
|
265
|
+
#
|
266
|
+
# @example
|
267
|
+
# require "google/cloud/pubsub"
|
268
|
+
#
|
269
|
+
# pubsub = Google::Cloud::PubSub.new
|
270
|
+
# schema = pubsub.schema "my-schema"
|
271
|
+
#
|
272
|
+
# schema.resource_full? #=> true
|
273
|
+
#
|
274
|
+
def resource_full?
|
275
|
+
resource? && @grpc.definition && !@grpc.definition.empty?
|
276
|
+
end
|
277
|
+
|
278
|
+
##
|
279
|
+
# @private New Schema from a Google::Cloud::PubSub::V1::Schema object.
|
280
|
+
def self.from_grpc grpc, service, view: nil
|
281
|
+
new grpc, service, view: view
|
282
|
+
end
|
283
|
+
|
284
|
+
##
|
285
|
+
# @private New reference Schema object without making an HTTP request.
|
286
|
+
def self.from_name name, view, service, options = {}
|
287
|
+
grpc = Google::Cloud::PubSub::V1::Schema.new name: service.schema_path(name, options)
|
288
|
+
from_grpc grpc, service, view: view
|
289
|
+
end
|
290
|
+
|
291
|
+
protected
|
292
|
+
|
293
|
+
##
|
294
|
+
# @private Raise an error unless an active connection to the service is available.
|
295
|
+
def ensure_service!
|
296
|
+
raise "Must have active connection to service" unless service
|
297
|
+
end
|
298
|
+
|
299
|
+
##
|
300
|
+
# Ensures a Google::Cloud::PubSub::V1::Schema object exists.
|
301
|
+
def ensure_grpc!
|
302
|
+
ensure_service!
|
303
|
+
reload! if reference?
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
Pubsub = PubSub unless const_defined? :Pubsub
|
309
|
+
end
|
310
|
+
end
|