Skip to content

Commit 0897616

Browse files
[fix][fn] Honour retainOrdering and retainKeyOrdering in the Go function runtime (#26414)
1 parent 9890872 commit 0897616

2 files changed

Lines changed: 116 additions & 4 deletions

File tree

pulsar-function-go/pf/instance.go

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,30 @@ func (gi *goInstance) getProducer(topicName string) (pulsar.Producer, error) {
303303
return producer, err
304304
}
305305

306+
// resolveSubscriptionType picks the consumer subscription type for the function.
307+
//
308+
// The ordering flags are applied after the explicit SubscriptionType, matching the Java and Python
309+
// runtimes: retainOrdering requires a single consumer per partition, so it selects Failover, and
310+
// retainKeyOrdering selects KeyShared. Ordering wins when both are set, which is the precedence
311+
// python_instance.py applies.
312+
//
313+
// EFFECTIVELY_ONCE needs no arm here: instanceConf.go refuses it before an instance is built.
314+
func resolveSubscriptionType(configured pb.SubscriptionType, retainOrdering,
315+
retainKeyOrdering bool) pulsar.SubscriptionType {
316+
subscriptionType := pulsar.Shared
317+
if int32(configured) == pb.SubscriptionType_value["FAILOVER"] {
318+
subscriptionType = pulsar.Failover
319+
}
320+
321+
if retainOrdering {
322+
subscriptionType = pulsar.Failover
323+
} else if retainKeyOrdering {
324+
subscriptionType = pulsar.KeyShared
325+
}
326+
327+
return subscriptionType
328+
}
329+
306330
// resolveNackRedeliveryDelay returns the negative-ack redelivery delay to apply, or zero to leave
307331
// the client default in place.
308332
//
@@ -319,10 +343,10 @@ func resolveNackRedeliveryDelay(delayMs uint64) time.Duration {
319343
}
320344

321345
func (gi *goInstance) setupConsumer() (chan pulsar.ConsumerMessage, error) {
322-
subscriptionType := pulsar.Shared
323-
if int32(gi.context.instanceConf.funcDetails.Source.SubscriptionType) == pb.SubscriptionType_value["FAILOVER"] {
324-
subscriptionType = pulsar.Failover
325-
}
346+
subscriptionType := resolveSubscriptionType(
347+
gi.context.instanceConf.funcDetails.Source.SubscriptionType,
348+
gi.context.instanceConf.funcDetails.RetainOrdering,
349+
gi.context.instanceConf.funcDetails.RetainKeyOrdering)
326350

327351
funcDetails := gi.context.instanceConf.funcDetails
328352
subscriptionName := funcDetails.Tenant + "/" + funcDetails.Namespace + "/" + funcDetails.Name
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
//
2+
// Licensed to the Apache Software Foundation (ASF) under one
3+
// or more contributor license agreements. See the NOTICE file
4+
// distributed with this work for additional information
5+
// regarding copyright ownership. The ASF licenses this file
6+
// to you under the Apache License, Version 2.0 (the
7+
// "License"); you may not use this file except in compliance
8+
// with the License. You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing,
13+
// software distributed under the License is distributed on an
14+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
// KIND, either express or implied. See the License for the
16+
// specific language governing permissions and limitations
17+
// under the License.
18+
//
19+
20+
package pf
21+
22+
import (
23+
"testing"
24+
25+
"github.com/apache/pulsar-client-go/pulsar"
26+
"github.com/stretchr/testify/assert"
27+
28+
pb "github.com/apache/pulsar/pulsar-function-go/pb"
29+
)
30+
31+
// The Go runtime previously read only SubscriptionType, so retainOrdering and retainKeyOrdering
32+
// were accepted and silently dropped: a function created with --retain-key-ordering ran on a
33+
// Shared subscription and lost per-key ordering. These pin the rules the Java and Python runtimes
34+
// apply.
35+
func TestResolveSubscriptionType(t *testing.T) {
36+
tests := []struct {
37+
name string
38+
configured pb.SubscriptionType
39+
retainOrdering bool
40+
retainKeyOrdering bool
41+
expected pulsar.SubscriptionType
42+
}{
43+
{
44+
name: "default is shared",
45+
configured: pb.SubscriptionType_SHARED,
46+
expected: pulsar.Shared,
47+
},
48+
{
49+
name: "explicit failover is honoured",
50+
configured: pb.SubscriptionType_FAILOVER,
51+
expected: pulsar.Failover,
52+
},
53+
{
54+
name: "retainOrdering selects failover",
55+
configured: pb.SubscriptionType_SHARED,
56+
retainOrdering: true,
57+
expected: pulsar.Failover,
58+
},
59+
{
60+
name: "retainKeyOrdering selects key_shared",
61+
configured: pb.SubscriptionType_SHARED,
62+
retainKeyOrdering: true,
63+
expected: pulsar.KeyShared,
64+
},
65+
{
66+
// python_instance.py applies retainOrdering first and only falls to retainKeyOrdering
67+
// in the else branch, so ordering wins. Pinned so the two runtimes cannot drift.
68+
name: "retainOrdering wins over retainKeyOrdering",
69+
configured: pb.SubscriptionType_SHARED,
70+
retainOrdering: true,
71+
retainKeyOrdering: true,
72+
expected: pulsar.Failover,
73+
},
74+
{
75+
name: "retainKeyOrdering overrides an explicit failover",
76+
configured: pb.SubscriptionType_FAILOVER,
77+
retainKeyOrdering: true,
78+
expected: pulsar.KeyShared,
79+
},
80+
}
81+
82+
for _, test := range tests {
83+
t.Run(test.name, func(t *testing.T) {
84+
assert.Equal(t, test.expected,
85+
resolveSubscriptionType(test.configured, test.retainOrdering, test.retainKeyOrdering))
86+
})
87+
}
88+
}

0 commit comments

Comments
 (0)