Skip to content

Commit 339976e

Browse files
authored
Classify CH ErrTooManyParts (#3915)
1 parent b647006 commit 339976e

File tree

2 files changed

+50
-1
lines changed

2 files changed

+50
-1
lines changed

flow/alerting/classifier.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ var (
5050
)
5151
// ID(a14c2a1c-edcd-5fcb-73be-bd04e09fccb7) not found in user directories
5252
ClickHouseNotFoundInUserDirsRe = regexp.MustCompile("ID\\([a-z0-9-]+\\) not found in `?user directories`?")
53+
ClickHouseTooManyPartsTableRe = regexp.MustCompile(`in table '(.+)'\.`)
5354
PostgresPublicationDoesNotExistRe = regexp.MustCompile(`publication ".*?" does not exist`)
5455
PostgresSnapshotDoesNotExistRe = regexp.MustCompile(`snapshot ".*?" does not exist`)
5556
PostgresWalSegmentRemovedRe = regexp.MustCompile(`requested WAL segment \w+ has already been removed`)
@@ -214,6 +215,9 @@ var (
214215
ErrorNotifyClickHouseSupportIsDisabledError = ErrorClass{
215216
Class: "NOTIFY_CLICKHOUSE_SUPPORT_IS_DISABLED_ERROR", action: NotifyUser,
216217
}
218+
ErrorNotifyTooManyPartsError = ErrorClass{
219+
Class: "NOTIFY_TOO_MANY_PARTS", action: NotifyUser,
220+
}
217221
// Catch-all for unclassified errors
218222
ErrorOther = ErrorClass{
219223
// These are unclassified and should not be exposed
@@ -884,6 +888,18 @@ func GetErrorClass(ctx context.Context, err error) (ErrorClass, ErrorInfo) {
884888
}
885889
case chproto.ErrSupportIsDisabled:
886890
return ErrorNotifyClickHouseSupportIsDisabledError, chErrorInfo
891+
case chproto.ErrTooManyParts:
892+
var additionalAttributes map[AdditionalErrorAttributeKey]string
893+
if matches := ClickHouseTooManyPartsTableRe.FindStringSubmatch(chException.Message); len(matches) > 1 {
894+
additionalAttributes = map[AdditionalErrorAttributeKey]string{
895+
ErrorAttributeKeyTable: matches[1],
896+
}
897+
}
898+
return ErrorNotifyTooManyPartsError, ErrorInfo{
899+
Source: chErrorInfo.Source,
900+
Code: chErrorInfo.Code,
901+
AdditionalAttributes: additionalAttributes,
902+
}
887903
}
888904
var normalizationErr *exceptions.NormalizationError
889905
if isClickHouseMvError(chException) {
@@ -995,7 +1011,7 @@ func GetErrorClass(ctx context.Context, err error) (ErrorClass, ErrorInfo) {
9951011
Code: "UNSUPPORTED_SCHEMA_CHANGE",
9961012
AdditionalAttributes: map[AdditionalErrorAttributeKey]string{
9971013
ErrorAttributeKeyTable: postgresReplicaIdentityIndexError.Table,
998-
ErrorAttributeKeyColumn: "n\a",
1014+
ErrorAttributeKeyColumn: "n/a",
9991015
},
10001016
}
10011017
}

flow/alerting/classifier_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,39 @@ func TestMySQLStreamingTLSHandshakeErrorShouldBeRecoverable(t *testing.T) {
728728
}, errInfo, "Unexpected error info")
729729
}
730730

731+
func TestClickHouseTooManyPartsWithTableName(t *testing.T) {
732+
err := &clickhouse.Exception{
733+
Code: int32(chproto.ErrTooManyParts),
734+
//nolint:lll
735+
Message: "Too many parts (3025 with average size of 65.51 MiB) in table 'ss_replica.posts_resync (db2b0f62-f577-4116-8b5d-e0f760a42bee)'. Merges are processing significantly slower than inserts",
736+
}
737+
errorClass, errInfo := GetErrorClass(t.Context(),
738+
exceptions.NewQRepSyncError(fmt.Errorf("QRepSync Error: %w", err), "", ""))
739+
assert.Equal(t, ErrorNotifyTooManyPartsError, errorClass)
740+
assert.Equal(t, ErrorInfo{
741+
Source: ErrorSourceClickHouse,
742+
Code: strconv.Itoa(int(chproto.ErrTooManyParts)),
743+
AdditionalAttributes: map[AdditionalErrorAttributeKey]string{
744+
ErrorAttributeKeyTable: "ss_replica.posts_resync (db2b0f62-f577-4116-8b5d-e0f760a42bee)",
745+
},
746+
}, errInfo)
747+
}
748+
749+
func TestClickHouseTooManyPartsWithoutTableName(t *testing.T) {
750+
err := &clickhouse.Exception{
751+
Code: int32(chproto.ErrTooManyParts),
752+
//nolint:lll
753+
Message: "Too many partitions for single INSERT block (more than 9999). The limit is controlled by 'max_partitions_per_insert_block' setting.",
754+
}
755+
errorClass, errInfo := GetErrorClass(t.Context(),
756+
exceptions.NewQRepSyncError(fmt.Errorf("QRepSync Error: %w", err), "", ""))
757+
assert.Equal(t, ErrorNotifyTooManyPartsError, errorClass)
758+
assert.Equal(t, ErrorInfo{
759+
Source: ErrorSourceClickHouse,
760+
Code: strconv.Itoa(int(chproto.ErrTooManyParts)),
761+
}, errInfo)
762+
}
763+
731764
func TestMySQLUnsupportedDDLShouldNotifyUser(t *testing.T) {
732765
err := exceptions.NewMySQLUnsupportedDDLError("test_db.test_table")
733766
errorClass, errInfo := GetErrorClass(t.Context(), fmt.Errorf("mysql error: %w", err))

0 commit comments

Comments
 (0)