Skip to content

Commit fa0486f

Browse files
committed
Merge remote-tracking branch 'upstream/main' into DBI-640/local-dev-env/e2e/toxy+split_pgcon
2 parents aff9d7d + b0735da commit fa0486f

35 files changed

Lines changed: 2077 additions & 1619 deletions

.tiltignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# When launching tests via VS Code, it builds binaries with this prefix in the test folder
2+
**/__debug_bin*

buf.gen.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ plugins:
99
- plugin: buf.build/protocolbuffers/go:v1.36.11
1010
out: flow/generated/protos
1111
opt: paths=source_relative
12-
- plugin: buf.build/grpc/go:v1.5.1
12+
- plugin: buf.build/grpc/go:v1.6.1
1313
out: flow/generated/protos
1414
opt:
1515
- paths=source_relative
@@ -24,12 +24,12 @@ plugins:
2424
out: nexus/pt/src/gen
2525
opt:
2626
- ignore_unknown_fields=true
27-
- plugin: buf.build/community/stephenh-ts-proto:v2.11.2
27+
- plugin: buf.build/community/stephenh-ts-proto:v2.11.6
2828
out: ui/grpc_generated
2929
opt:
3030
- esModuleInterop=true
3131
- outputServices=none
32-
- plugin: buf.build/grpc-ecosystem/gateway:v2.27.7
32+
- plugin: buf.build/grpc-ecosystem/gateway:v2.28.0
3333
out: flow/generated/protos
3434
opt:
3535
- paths=source_relative

flow/activities/flowable.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -827,21 +827,24 @@ func (a *FlowableActivity) DropFlowSource(ctx context.Context, req *protos.DropF
827827
ctx = context.WithValue(ctx, shared.FlowNameKey, req.FlowJobName)
828828
srcConn, srcClose, err := connectors.GetByNameAs[connectors.CDCPullConnectorCore](ctx, nil, a.CatalogPool, req.PeerName)
829829
if err != nil {
830-
var notFound *exceptions.NotFoundError
831-
if errors.As(err, &notFound) {
830+
if _, ok := errors.AsType[*exceptions.NotFoundError](err); ok {
832831
logger := internal.LoggerFromCtx(ctx)
833832
logger.Warn("peer missing, skipping", slog.String("peer", req.PeerName))
834833
return nil
835834
}
835+
if _, ok := errors.AsType[*exceptions.AuthError](err); ok {
836+
logger := internal.LoggerFromCtx(ctx)
837+
logger.Warn("auth error, skipping to avoid triggering security tools", slog.String("peer", req.PeerName))
838+
return nil
839+
}
836840
return a.Alerter.LogFlowError(ctx, req.FlowJobName,
837841
exceptions.NewDropFlowError(fmt.Errorf("[DropFlowSource] failed to get source connector: %w", err)),
838842
)
839843
}
840844
defer srcClose(ctx)
841845

842846
if err := srcConn.PullFlowCleanup(ctx, req.FlowJobName); err != nil {
843-
var dnsErr *net.DNSError
844-
if errors.As(err, &dnsErr) && dnsErr.IsNotFound {
847+
if dnsErr, ok := errors.AsType[*net.DNSError](err); ok && dnsErr.IsNotFound {
845848
a.Alerter.LogFlowWarning(ctx, req.FlowJobName, fmt.Errorf("[DropFlowSource] hostname not found, skipping: %w", err))
846849
return nil
847850
} else {

flow/activities/flowable_core.go

Lines changed: 53 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -728,58 +728,64 @@ func (a *FlowableActivity) normalizeLoop(
728728
defer normalizeWaiting.Store(false)
729729

730730
for {
731-
normalizeWaiting.Store(true)
732-
ch := normalizeRequests.Wait()
733-
if ch == nil {
734-
logger.Info("[normalize-loop] lastChan closed")
735-
return
736-
}
737-
select {
738-
case <-syncDone:
739-
logger.Info("[normalize-loop] syncDone closed")
740-
return
741-
case <-ctx.Done():
742-
logger.Info("[normalize-loop] context closed")
743-
return
744-
case <-ch:
745-
reqBatchID := normalizeRequests.Load()
746-
lastNormalizedBatchID := normalizingBatchID.Load()
747-
if reqBatchID <= lastNormalizedBatchID {
731+
// Check for pending work before waiting on the channel.
732+
// This avoids a race where Update() replaces the channel while we're
733+
// processing, causing Wait() to return the new (unclosed) channel
734+
// and missing the signal entirely until the next Update.
735+
reqBatchID := normalizeRequests.Load()
736+
lastNormalizedBatchID := normalizingBatchID.Load()
737+
if reqBatchID <= lastNormalizedBatchID {
738+
normalizeWaiting.Store(true)
739+
ch := normalizeRequests.Wait()
740+
if ch == nil {
741+
logger.Info("[normalize-loop] lastChan closed")
742+
return
743+
}
744+
select {
745+
case <-syncDone:
746+
logger.Info("[normalize-loop] syncDone closed")
747+
return
748+
case <-ctx.Done():
749+
logger.Info("[normalize-loop] context closed")
750+
return
751+
case <-ch:
748752
continue
749753
}
750-
retryInterval := time.Minute
751-
retryLoop:
752-
for {
753-
normalizingBatchID.Store(reqBatchID)
754-
if err := a.startNormalize(ctx, config, reqBatchID, normalizeResponses); err != nil {
755-
_ = a.Alerter.LogFlowError(ctx, config.FlowJobName, err)
756-
for {
757-
// update req to latest normalize request & retry
758-
select {
759-
case <-syncDone:
760-
logger.Info("[normalize-loop] syncDone closed before retry")
761-
return
762-
case <-ctx.Done():
763-
logger.Info("[normalize-loop] context closed before retry")
764-
return
765-
default:
766-
time.Sleep(retryInterval)
767-
retryInterval = min(retryInterval*2, 5*time.Minute)
768-
// record the last normalized batch ID even if retry fails to populate metrics consistently
769-
a.OtelManager.Metrics.LastNormalizedBatchIdGauge.Record(
770-
ctx, lastNormalizedBatchID, metric.WithAttributeSet(attribute.NewSet(
771-
attribute.String(otel_metrics.FlowNameKey, config.FlowJobName),
772-
)))
773-
reqBatchID = normalizeRequests.Load()
774-
continue retryLoop
775-
}
754+
}
755+
normalizeWaiting.Store(false)
756+
757+
retryInterval := time.Minute
758+
retryLoop:
759+
for {
760+
normalizingBatchID.Store(reqBatchID)
761+
if err := a.startNormalize(ctx, config, reqBatchID, normalizeResponses); err != nil {
762+
_ = a.Alerter.LogFlowError(ctx, config.FlowJobName, err)
763+
for {
764+
// update req to latest normalize request & retry
765+
select {
766+
case <-syncDone:
767+
logger.Info("[normalize-loop] syncDone closed before retry")
768+
return
769+
case <-ctx.Done():
770+
logger.Info("[normalize-loop] context closed before retry")
771+
return
772+
default:
773+
time.Sleep(retryInterval)
774+
retryInterval = min(retryInterval*2, 5*time.Minute)
775+
// record the last normalized batch ID even if retry fails to populate metrics consistently
776+
a.OtelManager.Metrics.LastNormalizedBatchIdGauge.Record(
777+
ctx, lastNormalizedBatchID, metric.WithAttributeSet(attribute.NewSet(
778+
attribute.String(otel_metrics.FlowNameKey, config.FlowJobName),
779+
)))
780+
reqBatchID = normalizeRequests.Load()
781+
continue retryLoop
776782
}
777783
}
778-
a.OtelManager.Metrics.LastNormalizedBatchIdGauge.Record(ctx, reqBatchID, metric.WithAttributeSet(attribute.NewSet(
779-
attribute.String(otel_metrics.FlowNameKey, config.FlowJobName),
780-
)))
781-
break
782784
}
785+
a.OtelManager.Metrics.LastNormalizedBatchIdGauge.Record(ctx, reqBatchID, metric.WithAttributeSet(attribute.NewSet(
786+
attribute.String(otel_metrics.FlowNameKey, config.FlowJobName),
787+
)))
788+
break
783789
}
784790
}
785791
}

flow/alerting/classifier.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,11 @@ var (
5252
`Cannot insert Avro decimal with scale \d+ and precision \d+ to ClickHouse type Decimal\(\d+, \d+\) with scale \d+ and precision \d+`,
5353
)
5454
// ID(a14c2a1c-edcd-5fcb-73be-bd04e09fccb7) not found in user directories
55-
ClickHouseNotFoundInUserDirsRe = regexp.MustCompile("ID\\([a-z0-9-]+\\) not found in `?user directories`?")
56-
ClickHouseTooManyPartsTableRe = regexp.MustCompile(`in table '(.+)'\.`)
55+
ClickHouseNotFoundInUserDirsRe = regexp.MustCompile("ID\\([a-z0-9-]+\\) not found in `?user directories`?")
56+
ClickHouseTooManyPartsTableRe = regexp.MustCompile(`in table '(.+)'\.`)
57+
ClickHouseObjectStorageIOErrorRe = regexp.MustCompile(
58+
`unspecified iostream_category error: while reading .+: While executing ReadFromObjectStorage`,
59+
)
5760
PostgresPublicationDoesNotExistRe = regexp.MustCompile(`publication ".*?" does not exist`)
5861
PostgresSnapshotDoesNotExistRe = regexp.MustCompile(`snapshot ".*?" does not exist`)
5962
PostgresWalSegmentRemovedRe = regexp.MustCompile(`requested WAL segment \w+ has already been removed`)
@@ -982,6 +985,10 @@ func GetErrorClass(ctx context.Context, err error) (ErrorClass, ErrorInfo) {
982985
chproto.ErrSocketTimeout,
983986
chproto.ErrTableIsReadOnly:
984987
return ErrorRetryRecoverable, chErrorInfo
988+
case chproto.ErrStdException:
989+
if ClickHouseObjectStorageIOErrorRe.MatchString(chException.Message) {
990+
return ErrorRetryRecoverable, chErrorInfo
991+
}
985992
case chproto.ErrTimeoutExceeded:
986993
if strings.HasSuffix(chException.Message, "distributed_ddl_task_timeout") {
987994
return ErrorRetryRecoverable, chErrorInfo

flow/alerting/classifier_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -978,3 +978,18 @@ func TestAuroraFailoverRONodeShouldBeRecoverable(t *testing.T) {
978978
Code: pgerrcode.ObjectNotInPrerequisiteState,
979979
}, errInfo)
980980
}
981+
982+
func TestClickHouseStdExceptionObjectStorageIOErrorShouldBeRecoverable(t *testing.T) {
983+
err := &clickhouse.Exception{
984+
Code: int32(chproto.ErrStdException),
985+
//nolint:lll
986+
Message: `std::__1::ios_base::failure: ios_base::clear: unspecified iostream_category error: while reading path/to/file.000000.avro: While executing ReadFromObjectStorage`,
987+
}
988+
errorClass, errInfo := GetErrorClass(t.Context(),
989+
exceptions.NewClickHouseQRepSyncError(fmt.Errorf("failed to sync records: %w", err), "tbl", "db"))
990+
assert.Equal(t, ErrorRetryRecoverable, errorClass)
991+
assert.Equal(t, ErrorInfo{
992+
Source: ErrorSourceClickHouse,
993+
Code: strconv.Itoa(int(chproto.ErrStdException)),
994+
}, errInfo)
995+
}

flow/connectors/core.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,8 @@ var (
669669

670670
_ GetTableSchemaConnector = &connpostgres.PostgresConnector{}
671671
_ GetTableSchemaConnector = &connmysql.MySqlConnector{}
672+
_ GetTableSchemaConnector = &connmongo.MongoConnector{}
673+
_ GetTableSchemaConnector = &connbigquery.BigQueryConnector{}
672674
_ GetTableSchemaConnector = &connsnowflake.SnowflakeConnector{}
673675
_ GetTableSchemaConnector = &connclickhouse.ClickHouseConnector{}
674676

@@ -696,6 +698,7 @@ var (
696698
_ QRepSyncConnector = &conns3.S3Connector{}
697699
_ QRepSyncConnector = &connclickhouse.ClickHouseConnector{}
698700
_ QRepSyncConnector = &connelasticsearch.ElasticsearchConnector{}
701+
_ QRepSyncConnector = &connpubsub.PubSubConnector{}
699702

700703
_ QRepSyncPgConnector = &connpostgres.PostgresConnector{}
701704

@@ -721,6 +724,7 @@ var (
721724
_ ValidationConnector = &connbigquery.BigQueryConnector{}
722725
_ ValidationConnector = &conns3.S3Connector{}
723726
_ ValidationConnector = &connmysql.MySqlConnector{}
727+
_ ValidationConnector = &connmongo.MongoConnector{}
724728

725729
_ MirrorSourceValidationConnector = &connpostgres.PostgresConnector{}
726730
_ MirrorSourceValidationConnector = &connmysql.MySqlConnector{}
@@ -729,6 +733,7 @@ var (
729733

730734
_ MirrorDestinationValidationConnector = &connclickhouse.ClickHouseConnector{}
731735
_ MirrorDestinationValidationConnector = &connpostgres.PostgresConnector{}
736+
_ MirrorDestinationValidationConnector = &connbigquery.BigQueryConnector{}
732737

733738
_ GetFlagsConnector = &connclickhouse.ClickHouseConnector{}
734739

flow/connectors/mongo/codec_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,11 @@ func TestMarshalDocument(t *testing.T) {
250250
input: bson.D{{Key: "date", Value: bson.DateTime(0)}},
251251
expected: `{"date":"1970-01-01T00:00:00Z"}`,
252252
},
253+
{
254+
desc: "bson.DateTime pre-1970",
255+
input: bson.D{{Key: "date", Value: bson.DateTime(-1)}},
256+
expected: `{"date":"1969-12-31T23:59:59.999Z"}`,
257+
},
253258
{
254259
desc: "bson.DateTime",
255260
input: bson.D{{Key: "date", Value: bson.DateTime(1672531200000)}}, // 2023-01-01 00:00:00 UTC

flow/connectors/mysql/mysql.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,9 @@ func (c *MySqlConnector) connect(ctx context.Context) (*client.Conn, error) {
168168
if conn == nil {
169169
argF := []client.Option{func(conn *client.Conn) error {
170170
if c.config.Compression > 0 {
171-
conn.SetCapability(mysql.CLIENT_COMPRESS)
171+
if err := conn.SetCapability(mysql.CLIENT_COMPRESS); err != nil {
172+
return err
173+
}
172174
}
173175
if !c.config.DisableTls {
174176
config, err := common.CreateTlsConfig(

0 commit comments

Comments
 (0)