Skip to content

Commit c4e2808

Browse files
authored
feat(pubsub): Add skip_lookup to Project#publisher to enable lazy loading (#32263)
docs(pubsub): Fix overview documentation URL --------- Co-authored-by: Dmitry Lebed <@d-lebed>
1 parent 6a3ab69 commit c4e2808

File tree

5 files changed

+152
-6
lines changed

5 files changed

+152
-6
lines changed

google-cloud-pubsub/OVERVIEW.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ into Admin Operations and Data Plane Operations.
3636
* **Data Plane Operations**: For the core functionality of publishing and receiving messages.
3737

3838
To learn more about Pub/Sub, read the [Google Cloud Pub/Sub Overview
39-
](https://cloud.google.com/pubsub/overview).
39+
](https://docs.cloud.google.com/pubsub/docs/overview).
4040

4141
## Admin Operations
4242

google-cloud-pubsub/lib/google/cloud/pubsub/project.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,17 @@ def iam
133133
# @param [Hash] async A hash of values to configure the topic's
134134
# {AsyncPublisher} that is created when {Publisher#publish_async}
135135
# is called. Optional.
136+
# @param [Boolean] skip_lookup Optionally create a {Publisher} object
137+
# without verifying the topic resource exists on the Pub/Sub
138+
# service. Calls made on this object will raise errors if the service
139+
# resource does not exist. Default is `false`.
136140
#
137141
# @return [Google::Cloud::PubSub::Publisher]
138142
#
139-
def publisher topic_name, project: nil, async: nil
143+
def publisher topic_name, project: nil, async: nil, skip_lookup: nil
140144
ensure_service!
141145
options = { project: project, async: async }
146+
return Publisher.from_name topic_name, service, options if skip_lookup
142147
grpc = topic_admin.get_topic topic: service.topic_path(topic_name, options)
143148
Publisher.from_grpc grpc, service, async: async
144149
end

google-cloud-pubsub/lib/google/cloud/pubsub/publisher.rb

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,56 @@ def async_publisher
8787
# `projects/{project_id}/topics/{topic_id}`.
8888
#
8989
def name
90+
return @resource_name if reference?
9091
@grpc.name
9192
end
9293

94+
##
95+
# Determines whether the publisher object was created with a resource
96+
# representation from the Pub/Sub service.
97+
#
98+
# @return [Boolean] `true` when the publisher was created with a resource
99+
# representation, `false` otherwise.
100+
#
101+
def reference?
102+
@grpc.nil?
103+
end
104+
105+
##
106+
# Determines whether the publisher object was created with a resource
107+
# representation from the Pub/Sub service.
108+
#
109+
# @return [Boolean] `true` when the publisher was created with a resource
110+
# representation, `false` otherwise.
111+
#
112+
def resource?
113+
!@grpc.nil?
114+
end
115+
116+
117+
##
118+
# Reloads the publisher with current data from the Pub/Sub service.
119+
#
120+
# @return [Google::Cloud::PubSub::Publisher] Returns the reloaded
121+
# publisher
122+
#
123+
# @example
124+
# require "google/cloud/pubsub"
125+
#
126+
# pubsub = Google::Cloud::PubSub.new
127+
#
128+
# publisher = pubsub.publisher "my-topic", skip_lookup: true
129+
#
130+
# publisher.reload!
131+
#
132+
def reload!
133+
ensure_service!
134+
topic_path = service.topic_path name
135+
@grpc = service.topic_admin.get_topic topic: topic_path
136+
@resource_name = nil
137+
self
138+
end
139+
93140
##
94141
# Publishes one or more messages to the publisher.
95142
#
@@ -166,7 +213,7 @@ def name
166213
#
167214
def publish data = nil, attributes = nil, ordering_key: nil, compress: nil, compression_bytes_threshold: nil,
168215
**extra_attrs, &block
169-
ensure_service!
216+
ensure_grpc!
170217
batch = BatchPublisher.new data,
171218
attributes,
172219
ordering_key,
@@ -290,8 +337,7 @@ def publish data = nil, attributes = nil, ordering_key: nil, compress: nil, comp
290337
# publisher.async_publisher.stop!
291338
#
292339
def publish_async data = nil, attributes = nil, ordering_key: nil, **extra_attrs, &callback
293-
ensure_service!
294-
340+
ensure_grpc!
295341
@async_publisher ||= AsyncPublisher.new name, service, **@async_opts
296342
@async_publisher.publish data, attributes, ordering_key: ordering_key, **extra_attrs, &callback
297343
end
@@ -351,6 +397,16 @@ def self.from_grpc grpc, service, async: nil
351397
end
352398
end
353399

400+
##
401+
# @private New reference {Publisher} from a topic name without making
402+
# a HTTP request.
403+
def self.from_name name, service, options = {}
404+
name = service.topic_path name, options
405+
from_grpc(nil, service, async: options[:async]).tap do |t|
406+
t.instance_variable_set :@resource_name, name
407+
end
408+
end
409+
354410
protected
355411

356412
##
@@ -364,6 +420,7 @@ def ensure_service!
364420
# Ensures a Google::Cloud::PubSub::V1::Topic object exists.
365421
def ensure_grpc!
366422
ensure_service!
423+
reload! if reference?
367424
end
368425
end
369426
end
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Copyright 2015 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+
require "helper"
16+
17+
describe Google::Cloud::PubSub::Publisher, :name, :mock_pubsub do
18+
let(:topic_name) { "topic-name-goes-here" }
19+
let(:full_topic_name) { topic_path topic_name }
20+
let(:topic_grpc_hash) { topic_hash topic_name }
21+
let(:topic_grpc) { Google::Cloud::PubSub::V1::Topic.new topic_grpc_hash }
22+
let(:publisher) { Google::Cloud::PubSub::Publisher.from_grpc topic_grpc, pubsub.service }
23+
24+
it "is not reference when created with an HTTP method" do
25+
_(publisher).wont_be :reference?
26+
_(publisher).must_be :resource?
27+
end
28+
29+
describe "reference publisher" do
30+
let :publisher do
31+
Google::Cloud::PubSub::Publisher.from_name topic_name, pubsub.service
32+
end
33+
34+
it "is reference" do
35+
_(publisher).must_be :reference?
36+
_(publisher).wont_be :resource?
37+
end
38+
end
39+
end

google-cloud-pubsub/test/google/cloud/pubsub/publisher_test.rb

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,4 +141,49 @@
141141
_(msgs.last.message_id).must_equal "msg2"
142142
_(msgs.last.attributes["format"]).must_equal "none"
143143
end
144-
end
144+
145+
it "can be created with skip_lookup: true" do
146+
mock = Minitest::Mock.new
147+
pubsub.service.mocked_topic_admin = mock
148+
149+
publisher = pubsub.publisher topic_name, skip_lookup: true
150+
151+
_(publisher.name).must_equal topic_path(topic_name)
152+
_(publisher).must_be :reference?
153+
154+
mock.verify
155+
end
156+
157+
it "reloads the resource when publishing if created with skip_lookup: true" do
158+
mock = Minitest::Mock.new
159+
pubsub.service.mocked_topic_admin = mock
160+
161+
publisher = pubsub.publisher topic_name, skip_lookup: true
162+
163+
_(publisher).must_be :reference?
164+
165+
mock.expect :get_topic, Google::Cloud::PubSub::V1::Topic.new(topic_hash(topic_name)) do |actual_topic|
166+
actual_topic == {topic: topic_path(topic_name)}
167+
end
168+
169+
# Expect publish to be called
170+
message = "new-message-here"
171+
encoded_msg = message.encode(Encoding::ASCII_8BIT)
172+
messages = [
173+
Google::Cloud::PubSub::V1::PubsubMessage.new(data: encoded_msg)
174+
]
175+
publish_res = Google::Cloud::PubSub::V1::PublishResponse.new({ message_ids: ["msg1"] })
176+
expected_request = {topic: topic_path(topic_name), messages: messages}
177+
178+
mock.expect :publish_internal, publish_res do |actual_request, actual_option|
179+
actual_request == expected_request && actual_option.nil?
180+
end
181+
182+
msg = publisher.publish message
183+
184+
_(publisher).wont_be :reference?
185+
_(msg.message_id).must_equal "msg1"
186+
187+
mock.verify
188+
end
189+
end

0 commit comments

Comments
 (0)