Skip to content

Commit 042151e

Browse files
passuiedyaron2
andauthored
Backporting fixes for #3609, #3529 (#3616)
Signed-off-by: Patrick Assuied <[email protected]> Co-authored-by: Yaron Schneider <[email protected]>
1 parent c3677e3 commit 042151e

File tree

4 files changed

+38
-7
lines changed

4 files changed

+38
-7
lines changed

common/component/kafka/consumer.go

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ limitations under the License.
1414
package kafka
1515

1616
import (
17+
"context"
1718
"errors"
1819
"fmt"
1920
"net/url"
@@ -32,6 +33,29 @@ type consumer struct {
3233
mutex sync.Mutex
3334
}
3435

36+
func notifyRecover(consumer *consumer, message *sarama.ConsumerMessage, session sarama.ConsumerGroupSession, b backoff.BackOff) error {
37+
for {
38+
if err := retry.NotifyRecover(func() error {
39+
return consumer.doCallback(session, message)
40+
}, b, func(err error, d time.Duration) {
41+
consumer.k.logger.Warnf("Error processing Kafka message: %s/%d/%d [key=%s]. Error: %v. Retrying...", message.Topic, message.Partition, message.Offset, asBase64String(message.Key), err)
42+
}, func() {
43+
consumer.k.logger.Infof("Successfully processed Kafka message after it previously failed: %s/%d/%d [key=%s]", message.Topic, message.Partition, message.Offset, asBase64String(message.Key))
44+
}); err != nil {
45+
// If the retry policy got interrupted, it could mean that either
46+
// the policy has reached its maximum number of attempts or the context has been cancelled.
47+
// There is a weird edge case where the error returned is a 'context canceled' error but the session.Context is not done.
48+
// This is a workaround to handle that edge case and reprocess the current message.
49+
if err == context.Canceled && session.Context().Err() == nil {
50+
consumer.k.logger.Warnf("Error processing Kafka message: %s/%d/%d [key=%s]. The error returned is 'context canceled' but the session context is not done. Retrying...")
51+
continue
52+
}
53+
return err
54+
}
55+
return nil
56+
}
57+
}
58+
3559
func (consumer *consumer) ConsumeClaim(session sarama.ConsumerGroupSession, claim sarama.ConsumerGroupClaim) error {
3660
b := consumer.k.backOffConfig.NewBackOffWithContext(session.Context())
3761
isBulkSubscribe := consumer.k.checkBulkSubscribe(claim.Topic())
@@ -83,13 +107,7 @@ func (consumer *consumer) ConsumeClaim(session sarama.ConsumerGroupSession, clai
83107
}
84108

85109
if consumer.k.consumeRetryEnabled {
86-
if err := retry.NotifyRecover(func() error {
87-
return consumer.doCallback(session, message)
88-
}, b, func(err error, d time.Duration) {
89-
consumer.k.logger.Warnf("Error processing Kafka message: %s/%d/%d [key=%s]. Error: %v. Retrying...", message.Topic, message.Partition, message.Offset, asBase64String(message.Key), err)
90-
}, func() {
91-
consumer.k.logger.Infof("Successfully processed Kafka message after it previously failed: %s/%d/%d [key=%s]", message.Topic, message.Partition, message.Offset, asBase64String(message.Key))
92-
}); err != nil {
110+
if err := notifyRecover(consumer, message, session, b); err != nil {
93111
consumer.k.logger.Errorf("Too many failed attempts at processing Kafka message: %s/%d/%d [key=%s]. Error: %v.", message.Topic, message.Partition, message.Offset, asBase64String(message.Key), err)
94112
}
95113
} else {

common/component/kafka/kafka.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,14 +208,17 @@ func (k *Kafka) Init(ctx context.Context, metadata map[string]string) error {
208208
k.consumeRetryInterval = meta.ConsumeRetryInterval
209209

210210
if meta.SchemaRegistryURL != "" {
211+
k.logger.Infof("Schema registry URL '%s' provided. Configuring the Schema Registry client.", meta.SchemaRegistryURL)
211212
k.srClient = srclient.CreateSchemaRegistryClient(meta.SchemaRegistryURL)
212213
// Empty password is a possibility
213214
if meta.SchemaRegistryAPIKey != "" {
214215
k.srClient.SetCredentials(meta.SchemaRegistryAPIKey, meta.SchemaRegistryAPISecret)
215216
}
217+
k.logger.Infof("Schema caching enabled: %v", meta.SchemaCachingEnabled)
216218
k.srClient.CachingEnabled(meta.SchemaCachingEnabled)
217219
if meta.SchemaCachingEnabled {
218220
k.latestSchemaCache = make(map[string]SchemaCacheEntry)
221+
k.logger.Debugf("Schema cache TTL: %v", meta.SchemaLatestVersionCacheTTL)
219222
k.latestSchemaCacheTTL = meta.SchemaLatestVersionCacheTTL
220223
}
221224
}
@@ -323,6 +326,7 @@ func (k *Kafka) getLatestSchema(topic string) (*srclient.Schema, *goavro.Codec,
323326
if ok && cacheEntry.expirationTime.After(time.Now()) {
324327
return cacheEntry.schema, cacheEntry.codec, nil
325328
}
329+
k.logger.Debugf("Cache not found or expired for subject %s. Fetching from registry...", subject)
326330
schema, errSchema := srClient.GetLatestSchema(subject)
327331
if errSchema != nil {
328332
return nil, nil, errSchema

common/component/kafka/kafka_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/stretchr/testify/require"
1414

1515
mock_srclient "github.com/dapr/components-contrib/common/component/kafka/mocks"
16+
"github.com/dapr/kit/logger"
1617
)
1718

1819
func TestGetValueSchemaType(t *testing.T) {
@@ -62,6 +63,7 @@ func TestDeserializeValue(t *testing.T) {
6263
k := Kafka{
6364
srClient: registry,
6465
schemaCachingEnabled: true,
66+
logger: logger.NewLogger("kafka_test"),
6567
}
6668

6769
schemaIDBytes := make([]byte, 4)
@@ -175,6 +177,7 @@ func TestSerializeValueCachingDisabled(t *testing.T) {
175177
k := Kafka{
176178
srClient: registry,
177179
schemaCachingEnabled: false,
180+
logger: logger.NewLogger("kafka_test"),
178181
}
179182

180183
t.Run("valueSchemaType not set, leave value as is", func(t *testing.T) {
@@ -250,6 +253,7 @@ func TestSerializeValueCachingEnabled(t *testing.T) {
250253
schemaCachingEnabled: true,
251254
latestSchemaCache: make(map[string]SchemaCacheEntry),
252255
latestSchemaCacheTTL: time.Minute * 5,
256+
logger: logger.NewLogger("kafka_test"),
253257
}
254258

255259
t.Run("valueSchemaType not set, leave value as is", func(t *testing.T) {
@@ -280,6 +284,7 @@ func TestLatestSchemaCaching(t *testing.T) {
280284
schemaCachingEnabled: true,
281285
latestSchemaCache: make(map[string]SchemaCacheEntry),
282286
latestSchemaCacheTTL: time.Second * 10,
287+
logger: logger.NewLogger("kafka_test"),
283288
}
284289

285290
m.EXPECT().GetLatestSchema(gomock.Eq("my-topic-value")).Return(schema, nil).Times(1)
@@ -302,6 +307,7 @@ func TestLatestSchemaCaching(t *testing.T) {
302307
schemaCachingEnabled: true,
303308
latestSchemaCache: make(map[string]SchemaCacheEntry),
304309
latestSchemaCacheTTL: time.Second * 1,
310+
logger: logger.NewLogger("kafka_test"),
305311
}
306312

307313
m.EXPECT().GetLatestSchema(gomock.Eq("my-topic-value")).Return(schema, nil).Times(2)
@@ -326,6 +332,7 @@ func TestLatestSchemaCaching(t *testing.T) {
326332
schemaCachingEnabled: false,
327333
latestSchemaCache: make(map[string]SchemaCacheEntry),
328334
latestSchemaCacheTTL: 0,
335+
logger: logger.NewLogger("kafka_test"),
329336
}
330337

331338
m.EXPECT().GetLatestSchema(gomock.Eq("my-topic-value")).Return(schema, nil).Times(2)

common/component/kafka/metadata.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,8 @@ func (k *Kafka) getKafkaMetadata(meta map[string]string) (*KafkaMetadata, error)
163163
ClientConnectionKeepAliveInterval: defaultClientConnectionKeepAliveInterval,
164164
HeartbeatInterval: 3 * time.Second,
165165
SessionTimeout: 10 * time.Second,
166+
SchemaCachingEnabled: true,
167+
SchemaLatestVersionCacheTTL: 5 * time.Minute,
166168
EscapeHeaders: false,
167169
}
168170

0 commit comments

Comments
 (0)