Skip to content

Commit ae89eba

Browse files
committed
Refactor pubsub protocol to use new upstream v2 library
See googleapis/google-cloud-go#12218 for reference Signed-off-by: Philipp Schuler <[email protected]>
1 parent 34f7f6f commit ae89eba

File tree

11 files changed

+114
-76
lines changed

11 files changed

+114
-76
lines changed

protocol/pubsub/v2/context/context.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
"strings"
1212
"time"
1313

14-
"cloud.google.com/go/pubsub"
14+
"cloud.google.com/go/pubsub/v2"
1515
)
1616

1717
// ProtocolContext allows a Receiver to understand the context of a request.

protocol/pubsub/v2/go.mod

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ toolchain go1.23.8
77
replace github.com/cloudevents/sdk-go/v2 => ../../../v2
88

99
require (
10-
cloud.google.com/go/pubsub v1.50.0
10+
cloud.google.com/go/pubsub/v2 v2.0.0
1111
github.com/cloudevents/sdk-go/v2 v2.16.1
1212
github.com/google/go-cmp v0.7.0
1313
github.com/stretchr/testify v1.11.0
1414
golang.org/x/sync v0.16.0
1515
google.golang.org/api v0.248.0
16-
google.golang.org/genproto v0.0.0-20250818200422-3122310a409c
1716
google.golang.org/grpc v1.75.0
17+
google.golang.org/protobuf v1.36.7
1818
)
1919

2020
require (
@@ -23,7 +23,6 @@ require (
2323
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
2424
cloud.google.com/go/compute/metadata v0.8.0 // indirect
2525
cloud.google.com/go/iam v1.5.2 // indirect
26-
cloud.google.com/go/pubsub/v2 v2.0.0 // indirect
2726
github.com/davecgh/go-spew v1.1.1 // indirect
2827
github.com/felixge/httpsnoop v1.0.4 // indirect
2928
github.com/go-logr/logr v1.4.3 // indirect
@@ -54,8 +53,8 @@ require (
5453
golang.org/x/sys v0.35.0 // indirect
5554
golang.org/x/text v0.28.0 // indirect
5655
golang.org/x/time v0.12.0 // indirect
56+
google.golang.org/genproto v0.0.0-20250818200422-3122310a409c // indirect
5757
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c // indirect
5858
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect
59-
google.golang.org/protobuf v1.36.8 // indirect
6059
gopkg.in/yaml.v3 v3.0.1 // indirect
6160
)

protocol/pubsub/v2/go.sum

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,6 @@ cloud.google.com/go/compute/metadata v0.8.0 h1:HxMRIbao8w17ZX6wBnjhcDkW6lTFpgcao
99
cloud.google.com/go/compute/metadata v0.8.0/go.mod h1:sYOGTp851OV9bOFJ9CH7elVvyzopvWQFNNghtDQ/Biw=
1010
cloud.google.com/go/iam v1.5.2 h1:qgFRAGEmd8z6dJ/qyEchAuL9jpswyODjA2lS+w234g8=
1111
cloud.google.com/go/iam v1.5.2/go.mod h1:SE1vg0N81zQqLzQEwxL2WI6yhetBdbNQuTvIKCSkUHE=
12-
cloud.google.com/go/kms v1.22.0 h1:dBRIj7+GDeeEvatJeTB19oYZNV0aj6wEqSIT/7gLqtk=
13-
cloud.google.com/go/kms v1.22.0/go.mod h1:U7mf8Sva5jpOb4bxYZdtw/9zsbIjrklYwPcvMk34AL8=
14-
cloud.google.com/go/longrunning v0.6.7 h1:IGtfDWHhQCgCjwQjV9iiLnUta9LBCo8R9QmAFsS/PrE=
15-
cloud.google.com/go/longrunning v0.6.7/go.mod h1:EAFV3IZAKmM56TyiE6VAP3VoTzhZzySwI/YI1s/nRsY=
16-
cloud.google.com/go/pubsub v1.50.0 h1:hnYpOIxVlgVD1Z8LN7est4DQZK3K6tvZNurZjIVjUe0=
17-
cloud.google.com/go/pubsub v1.50.0/go.mod h1:Di2Y+nqXBpIS+dXUEJPQzLh8PbIQZMLE9IVUFhf2zmM=
1812
cloud.google.com/go/pubsub/v2 v2.0.0 h1:0qS6mRJ41gD1lNmM/vdm6bR7DQu6coQcVwD+VPf0Bz0=
1913
cloud.google.com/go/pubsub/v2 v2.0.0/go.mod h1:0aztFxNzVQIRSZ8vUr79uH2bS3jwLebwK6q1sgEub+E=
2014
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
@@ -193,8 +187,8 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
193187
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
194188
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
195189
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
196-
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
197-
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
190+
google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A=
191+
google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
198192
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
199193
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
200194
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=

protocol/pubsub/v2/internal/connection.go

Lines changed: 70 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,24 @@ import (
1313
"sync"
1414
"time"
1515

16-
"cloud.google.com/go/pubsub"
16+
"cloud.google.com/go/pubsub/v2"
17+
"cloud.google.com/go/pubsub/v2/apiv1/pubsubpb"
1718
pscontext "github.com/cloudevents/sdk-go/protocol/pubsub/v2/context"
1819
"github.com/cloudevents/sdk-go/v2/binding"
20+
"google.golang.org/grpc/codes"
21+
"google.golang.org/grpc/status"
22+
"google.golang.org/protobuf/types/known/durationpb"
1923
)
2024

2125
type topicInfo struct {
22-
topic *pubsub.Topic
26+
topic *pubsub.Publisher
2327
wasCreated bool
2428
once sync.Once
2529
err error
2630
}
2731

2832
type subInfo struct {
29-
sub *pubsub.Subscription
33+
sub *pubsub.Subscriber
3034
wasCreated bool
3135
once sync.Once
3236
err error
@@ -89,8 +93,35 @@ const (
8993
var DefaultReceiveSettings = pubsub.ReceiveSettings{
9094
// Pubsub default receive settings will fill in other values.
9195
// https://godoc.org/cloud.google.com/go/pubsub#Client.Subscription
96+
}
9297

93-
Synchronous: false,
98+
// pubsub/v2 dropped Exists methods and suggests optimistically using GetTopic instead
99+
func topicExists(ctx context.Context, client *pubsub.Client, topicID string) (bool, error) {
100+
// Check if the topic exists.
101+
_, err := client.TopicAdminClient.GetTopic(ctx, &pubsubpb.GetTopicRequest{
102+
Topic: fmt.Sprintf("projects/%s/topics/%s", client.Project(), topicID),
103+
})
104+
if err != nil {
105+
if st, ok := status.FromError(err); ok && st.Code() == codes.NotFound {
106+
return false, nil
107+
}
108+
return false, fmt.Errorf("unable to get topic %q, %v", topicID, err)
109+
}
110+
return true, nil
111+
}
112+
113+
func subscriptionExists(ctx context.Context, client *pubsub.Client, subID string) (bool, error) {
114+
// Check if the subscription exists.
115+
_, err := client.SubscriptionAdminClient.GetSubscription(ctx, &pubsubpb.GetSubscriptionRequest{
116+
Subscription: fmt.Sprintf("projects/%s/subscriptions/%s", client.Project(), subID),
117+
})
118+
if err != nil {
119+
if st, ok := status.FromError(err); ok && st.Code() == codes.NotFound {
120+
return false, nil
121+
}
122+
return false, fmt.Errorf("unable to get subscription %q, %v", subID, err)
123+
}
124+
return true, nil
94125
}
95126

96127
func (c *Connection) getOrCreateTopicInfo(ctx context.Context, getAlreadyOpenOnly bool) (*topicInfo, error) {
@@ -110,9 +141,7 @@ func (c *Connection) getOrCreateTopicInfo(ctx context.Context, getAlreadyOpenOnl
110141
// Make sure the topic structure is initialized at most once.
111142
ti.once.Do(func() {
112143
var ok bool
113-
// Load the topic.
114-
topic := c.Client.Topic(c.TopicID)
115-
ok, ti.err = topic.Exists(ctx)
144+
ok, ti.err = topicExists(ctx, c.Client, c.TopicID)
116145
if ti.err != nil {
117146
return
118147
}
@@ -122,14 +151,17 @@ func (c *Connection) getOrCreateTopicInfo(ctx context.Context, getAlreadyOpenOnl
122151
ti.err = fmt.Errorf("protocol not allowed to create topic %q", c.TopicID)
123152
return
124153
}
125-
topic, ti.err = c.Client.CreateTopic(ctx, c.TopicID)
154+
_, ti.err = c.Client.TopicAdminClient.CreateTopic(ctx, &pubsubpb.Topic{
155+
Name: fmt.Sprintf("projects/%s/topics/%s", c.Client.Project(), c.TopicID),
156+
})
126157
if ti.err != nil {
127158
return
128159
}
129160
ti.wasCreated = true
130161
}
131-
// Success.
132-
ti.topic = topic
162+
163+
// If the topic exists, we can use it
164+
ti.topic = c.Client.Publisher(c.TopicID)
133165

134166
// EnableMessageOrdering is a runtime parameter only and not part of the topic
135167
// Pub/Sub configuration. The Pub/Sub SDK requires this to be set to accept Pub/Sub
@@ -151,7 +183,7 @@ func (c *Connection) getOrCreateTopicInfo(ctx context.Context, getAlreadyOpenOnl
151183
return ti, nil
152184
}
153185

154-
func (c *Connection) getOrCreateTopic(ctx context.Context, getAlreadyOpenOnly bool) (*pubsub.Topic, error) {
186+
func (c *Connection) getOrCreateTopic(ctx context.Context, getAlreadyOpenOnly bool) (*pubsub.Publisher, error) {
155187
ti, err := c.getOrCreateTopicInfo(ctx, getAlreadyOpenOnly)
156188
if ti != nil {
157189
return ti.topic, nil
@@ -170,12 +202,17 @@ func (c *Connection) DeleteTopic(ctx context.Context) error {
170202
if !ti.wasCreated {
171203
return errors.New("topic was not created by pubsub protocol")
172204
}
173-
if err := ti.topic.Delete(ctx); err != nil {
174-
return err
175-
}
176205

206+
// Stop the publisher and send all messages before deleting the topic
177207
ti.topic.Stop()
178208

209+
err = c.Client.TopicAdminClient.DeleteTopic(ctx, &pubsubpb.DeleteTopicRequest{
210+
Topic: fmt.Sprintf("projects/%s/topics/%s", c.Client.Project(), ti.topic.ID()),
211+
})
212+
if err != nil {
213+
return err
214+
}
215+
179216
c.initLock.Lock()
180217
if ti == c.topicInfo {
181218
c.topicInfo = nil
@@ -211,10 +248,8 @@ func (c *Connection) getOrCreateSubscriptionInfo(ctx context.Context, getAlready
211248

212249
// Make sure the subscription structure is initialized at most once.
213250
si.once.Do(func() {
214-
// Load the subscription.
215251
var ok bool
216-
sub := c.Client.Subscription(c.SubscriptionID)
217-
ok, si.err = sub.Exists(ctx)
252+
ok, si.err = subscriptionExists(ctx, c.Client, c.SubscriptionID)
218253
if si.err != nil {
219254
return
220255
}
@@ -226,7 +261,7 @@ func (c *Connection) getOrCreateSubscriptionInfo(ctx context.Context, getAlready
226261
}
227262

228263
// Load the topic.
229-
var topic *pubsub.Topic
264+
var topic *pubsub.Publisher
230265
topic, si.err = c.getOrCreateTopic(ctx, false)
231266
if si.err != nil {
232267
return
@@ -235,26 +270,29 @@ func (c *Connection) getOrCreateSubscriptionInfo(ctx context.Context, getAlready
235270
// Create a new subscription to the previously created topic
236271
// with the given name.
237272
// TODO: allow to use push config + allow setting the SubscriptionConfig.
238-
sub, si.err = c.Client.CreateSubscription(ctx, c.SubscriptionID, pubsub.SubscriptionConfig{
239-
Topic: topic,
240-
AckDeadline: *c.AckDeadline,
241-
RetentionDuration: *c.RetentionDuration,
242-
EnableMessageOrdering: c.MessageOrdering,
243-
Filter: c.Filter,
273+
_, si.err = c.Client.SubscriptionAdminClient.CreateSubscription(ctx, &pubsubpb.Subscription{
274+
Name: fmt.Sprintf("projects/%s/subscriptions/%s", c.Client.Project(), c.SubscriptionID),
275+
Topic: fmt.Sprintf("projects/%s/topics/%s", c.Client.Project(), topic.ID()),
276+
AckDeadlineSeconds: int32(c.AckDeadline.Seconds()),
277+
MessageRetentionDuration: durationpb.New(*c.RetentionDuration),
278+
EnableMessageOrdering: c.MessageOrdering,
279+
Filter: c.Filter,
244280
})
245281
if si.err != nil {
246282
return
247283
}
248284

249285
si.wasCreated = true
250286
}
287+
288+
// Success.
289+
si.sub = c.Client.Subscriber(c.SubscriptionID)
290+
251291
if c.ReceiveSettings == nil {
252-
sub.ReceiveSettings = DefaultReceiveSettings
292+
si.sub.ReceiveSettings = DefaultReceiveSettings
253293
} else {
254-
sub.ReceiveSettings = *c.ReceiveSettings
294+
si.sub.ReceiveSettings = *c.ReceiveSettings
255295
}
256-
// Success.
257-
si.sub = sub
258296
})
259297
if si.sub == nil {
260298
// Initialization failed, remove this attempt so that future callers
@@ -269,7 +307,7 @@ func (c *Connection) getOrCreateSubscriptionInfo(ctx context.Context, getAlready
269307
return si, nil
270308
}
271309

272-
func (c *Connection) getOrCreateSubscription(ctx context.Context, getAlreadyOpenOnly bool) (*pubsub.Subscription, error) {
310+
func (c *Connection) getOrCreateSubscription(ctx context.Context, getAlreadyOpenOnly bool) (*pubsub.Subscriber, error) {
273311
si, err := c.getOrCreateSubscriptionInfo(ctx, getAlreadyOpenOnly)
274312
if si != nil {
275313
return si.sub, nil
@@ -289,7 +327,9 @@ func (c *Connection) DeleteSubscription(ctx context.Context) error {
289327
if !si.wasCreated {
290328
return errors.New("subscription was not created by pubsub protocol")
291329
}
292-
if err := si.sub.Delete(ctx); err != nil {
330+
if err := c.Client.SubscriptionAdminClient.DeleteSubscription(ctx, &pubsubpb.DeleteSubscriptionRequest{
331+
Subscription: fmt.Sprintf("projects/%s/subscriptions/%s", c.Client.Project(), si.sub.ID()),
332+
}); err != nil {
293333
return err
294334
}
295335

0 commit comments

Comments
 (0)