Some checks failed
go: build dev binaries / cleanup (push) Successful in 4s
Codespell / Check for spelling errors (push) Failing after 3s
docker: build dev containers / build-rust-binaries (amd64, x86_64-unknown-linux-musl) (push) Failing after 3s
docker: build dev containers / build-dev-containers (push) Has been skipped
docker: build dev containers / build-rust-binaries (arm64, true, aarch64-unknown-linux-musl) (push) Failing after 3s
End to End / FUSE Mount (push) Failing after 2s
EC Integration Tests / EC Integration Tests (push) Failing after 30s
FUSE DLM Integration Tests / FUSE DLM Integration Tests (push) Failing after 3s
FUSE Volume Server Failover Tests / FUSE Volume Server Failover (push) Failing after 3s
FUSE Integration Tests / FUSE Integration Testing (push) Failing after 2s
FUSE P2P Peer Chunk Sharing Integration Tests / FUSE P2P Peer Chunk Sharing (push) Failing after 3s
go: build binary / Go Vet (push) Failing after 2s
go: build binary / Go Vet 32-bit (push) Failing after 3s
go: build binary / Build (push) Failing after 4s
go: build binary / Build cross-platform (freebsd/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (darwin/arm64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/arm64) (push) Failing after 3s
go: build binary / Test (push) Failing after 2s
go: build binary / Test 32-bit (push) Failing after 3s
helm: lint and test charts / lint-test (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (11) (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (17) (push) Failing after 3s
go: build dev binaries / build_dev_linux_windows (amd64, linux) (push) Failing after 2s
go: build dev binaries / build_dev_linux_windows (amd64, windows) (push) Failing after 3s
go: build dev binaries / build_dev_darwin (amd64, darwin) (push) Has been skipped
go: build dev binaries / build_dev_darwin (arm64, darwin) (push) Has been skipped
Java Client Unit Tests / Java Unit Tests (11) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (17) (push) Failing after 2s
Java Client Unit Tests / Java Unit Tests (21) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (8) (push) Failing after 3s
Kafka Quick Test (Load Test with Schema Registry) / Kafka Client Load Test (Quick) (push) Failing after 3s
Kafka Gateway Tests / Kafka Unit Tests (unit-tests-1) (push) Failing after 11s
Kafka Gateway Tests / Kafka Integration Tests (Critical) (integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka End-to-End Tests (with SMQ) (e2e-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Consumer Group Tests (Highly Isolated) (consumer-group-1) (push) Failing after 2s
Kafka Gateway Tests / Kafka Client Compatibility (with SMQ) (client-compat-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka SMQ Integration Tests (Full Stack) (smq-integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Protocol Tests (Isolated) (protocol-1) (push) Failing after 3s
KMS Tests / KMS Provider Integration Tests (push) Failing after 2s
KMS Tests / S3 KMS End-to-End Tests (push) Failing after 3s
Master Cold Start Tests / Master Cold Start Tests (push) Failing after 4s
Metadata Subscribe Integration Tests / Metadata Subscribe Integration Tests (push) Failing after 3s
Multi-Master Tests / Multi-Master Failover Tests (push) Failing after 3s
Performance / CPU and Heap Profile (push) Failing after 2s
Performance / S3 Read/Write Benchmark (rust volume) (push) Failing after 3s
pjdfstest POSIX Compliance / pjdfstest (push) Failing after 2s
Plugin Worker Integration Tests / Plugin Worker: erasure_coding (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: vacuum (push) Failing after 3s
Rust Volume Server Tests / Rust Integration Tests (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 1) (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 1) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 3) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Distributed Tests (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Performance Tests (push) Failing after 3s
Performance / Throughput Benchmark (go volume) (push) Failing after 3s
Performance / Throughput Benchmark (rust volume) (push) Failing after 2s
Performance / S3 Read/Write Benchmark (go volume) (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: volume_balance (push) Failing after 3s
PostgreSQL Gateway Tests / PostgreSQL Basic Tests (push) Failing after 3s
Rust Volume Server Tests / Rust Unit Tests (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 3) (push) Failing after 3s
Rust Plugin Worker Tests / Rust Plugin Worker Build and Unit Tests (push) Failing after 3s
rust: build dev volume server binaries / cleanup (push) Successful in 3s
S3 ETag and ACL Tests / S3 ETag + ACL Integration Tests (push) Failing after 3s
S3 IAM Integration Tests / IAM Unit Tests (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (advanced) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (basic) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (group) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (policy-enforcement) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (sts) (push) Failing after 4s
S3 Keycloak Integration Tests / S3 Keycloak Integration Tests (push) Failing after 3s
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.11) (push) Failing after 3s
S3 PyArrow Parquet Tests / Go Unit Tests (Implicit Directory) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.12) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-amd64, x86_64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-arm64, aarch64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-linux (linux-amd64, x86_64-unknown-linux-gnu) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.9) (push) Has been cancelled
S3 Proxy Signature Tests / S3 Proxy Signature Verification Tests (push) Has been cancelled
S3 SDK V2 Route Disambiguation Tests / S3 SDK V2 Routing Tests (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (quick) (push) Has been cancelled
S3 SSE Tests / S3 SSE Compatibility Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Metadata Persistence Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Copy Operations Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Multipart Upload Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Performance Test (push) Has been cancelled
S3 SSE Tests / S3 Volume Encryption Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (comprehensive) (push) Has been cancelled
Spark Integration Tests / Spark Integration Tests (push) Failing after 2s
Telemetry Integration Tests / telemetry-integration-test (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 1) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 1) (push) Failing after 3s
Ceph S3 tests / Basic S3 tests (KV store) (push) Has been cancelled
Ceph S3 tests / S3 Versioning & Object Lock tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Unit Tests (push) Failing after 3s
Ceph S3 tests / S3 CORS tests (push) Has been cancelled
Ceph S3 tests / SeaweedFS Custom S3 Copy tests (push) Has been cancelled
Ceph S3 tests / Basic S3 tests (SQL store) (push) Has been cancelled
test s3 over https using aws-cli / awscli-tests (push) Has been cancelled
TLS Rotation Integration Tests / TLS Rotation Integration Tests (push) Has been cancelled
Vacuum Integration Tests / Vacuum Integration Tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Variables Integration Tests (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (advanced-policy) (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (basic-policy) (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (contextual-policy) (push) Failing after 4s
S3 Policy Integration Tests / Trusted Proxy Detection Tests (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Shell Integration Tests (push) Failing after 3s
Samba on FUSE Integration / samba-integration (push) Failing after 2s
SFTP Integration Tests / SFTP Integration Testing (push) Failing after 3s
terraform: validate and test modules / fmt, validate, plan-level tests (push) Failing after 3s
terraform: validate and test modules / local cluster smoke test (real weed) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 3) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 2) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 2) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 3) (push) Failing after 5s
mount: windows conformance / WinFsp conformance (push) Has been cancelled
mount: windows / Mount on Windows (push) Has been cancelled
586 lines
19 KiB
Go
586 lines
19 KiB
Go
package protocol
|
|
|
|
import (
|
|
"context"
|
|
"encoding/binary"
|
|
"net"
|
|
"time"
|
|
)
|
|
|
|
// Kafka Protocol Error Codes
|
|
// Based on Apache Kafka protocol specification
|
|
const (
|
|
// Success
|
|
ErrorCodeNone int16 = 0
|
|
|
|
// General server errors
|
|
ErrorCodeUnknownServerError int16 = -1
|
|
ErrorCodeOffsetOutOfRange int16 = 1
|
|
ErrorCodeCorruptMessage int16 = 3 // Also UNKNOWN_TOPIC_OR_PARTITION
|
|
ErrorCodeUnknownTopicOrPartition int16 = 3
|
|
ErrorCodeInvalidFetchSize int16 = 4
|
|
ErrorCodeLeaderNotAvailable int16 = 5
|
|
ErrorCodeNotLeaderOrFollower int16 = 6 // Formerly NOT_LEADER_FOR_PARTITION
|
|
ErrorCodeRequestTimedOut int16 = 7
|
|
ErrorCodeBrokerNotAvailable int16 = 8
|
|
ErrorCodeReplicaNotAvailable int16 = 9
|
|
ErrorCodeMessageTooLarge int16 = 10
|
|
ErrorCodeStaleControllerEpoch int16 = 11
|
|
ErrorCodeOffsetMetadataTooLarge int16 = 12
|
|
ErrorCodeNetworkException int16 = 13
|
|
ErrorCodeOffsetLoadInProgress int16 = 14
|
|
ErrorCodeGroupLoadInProgress int16 = 15
|
|
ErrorCodeNotCoordinatorForGroup int16 = 16
|
|
ErrorCodeNotCoordinatorForTransaction int16 = 17
|
|
|
|
// Consumer group coordination errors
|
|
ErrorCodeIllegalGeneration int16 = 22
|
|
ErrorCodeInconsistentGroupProtocol int16 = 23
|
|
ErrorCodeInvalidGroupID int16 = 24
|
|
ErrorCodeUnknownMemberID int16 = 25
|
|
ErrorCodeInvalidSessionTimeout int16 = 26
|
|
ErrorCodeRebalanceInProgress int16 = 27
|
|
ErrorCodeInvalidCommitOffsetSize int16 = 28
|
|
ErrorCodeTopicAuthorizationFailed int16 = 29
|
|
ErrorCodeGroupAuthorizationFailed int16 = 30
|
|
ErrorCodeClusterAuthorizationFailed int16 = 31
|
|
ErrorCodeInvalidTimestamp int16 = 32
|
|
ErrorCodeUnsupportedSASLMechanism int16 = 33
|
|
ErrorCodeIllegalSASLState int16 = 34
|
|
ErrorCodeUnsupportedVersion int16 = 35
|
|
|
|
// Topic management errors
|
|
ErrorCodeTopicAlreadyExists int16 = 36
|
|
ErrorCodeInvalidPartitions int16 = 37
|
|
ErrorCodeInvalidReplicationFactor int16 = 38
|
|
ErrorCodeInvalidReplicaAssignment int16 = 39
|
|
ErrorCodeInvalidConfig int16 = 40
|
|
ErrorCodeNotController int16 = 41
|
|
ErrorCodeInvalidRecord int16 = 42
|
|
ErrorCodePolicyViolation int16 = 43
|
|
ErrorCodeOutOfOrderSequenceNumber int16 = 44
|
|
ErrorCodeDuplicateSequenceNumber int16 = 45
|
|
ErrorCodeInvalidProducerEpoch int16 = 46
|
|
ErrorCodeInvalidTxnState int16 = 47
|
|
ErrorCodeInvalidProducerIDMapping int16 = 48
|
|
ErrorCodeInvalidTransactionTimeout int16 = 49
|
|
ErrorCodeConcurrentTransactions int16 = 50
|
|
|
|
// Connection and timeout errors
|
|
ErrorCodeConnectionRefused int16 = 60 // Custom for connection issues
|
|
ErrorCodeConnectionTimeout int16 = 61 // Custom for connection timeouts
|
|
ErrorCodeReadTimeout int16 = 62 // Custom for read timeouts
|
|
ErrorCodeWriteTimeout int16 = 63 // Custom for write timeouts
|
|
|
|
// Consumer group specific errors
|
|
ErrorCodeMemberIDRequired int16 = 79
|
|
ErrorCodeFencedInstanceID int16 = 82
|
|
ErrorCodeGroupMaxSizeReached int16 = 84
|
|
ErrorCodeUnstableOffsetCommit int16 = 95
|
|
)
|
|
|
|
// ErrorInfo contains metadata about a Kafka error
|
|
type ErrorInfo struct {
|
|
Code int16
|
|
Name string
|
|
Description string
|
|
Retriable bool
|
|
}
|
|
|
|
// KafkaErrors maps error codes to their metadata
|
|
var KafkaErrors = map[int16]ErrorInfo{
|
|
ErrorCodeNone: {
|
|
Code: ErrorCodeNone, Name: "NONE", Description: "No error", Retriable: false,
|
|
},
|
|
ErrorCodeUnknownServerError: {
|
|
Code: ErrorCodeUnknownServerError, Name: "UNKNOWN_SERVER_ERROR",
|
|
Description: "Unknown server error", Retriable: true,
|
|
},
|
|
ErrorCodeOffsetOutOfRange: {
|
|
Code: ErrorCodeOffsetOutOfRange, Name: "OFFSET_OUT_OF_RANGE",
|
|
Description: "Offset out of range", Retriable: false,
|
|
},
|
|
ErrorCodeUnknownTopicOrPartition: {
|
|
Code: ErrorCodeUnknownTopicOrPartition, Name: "UNKNOWN_TOPIC_OR_PARTITION",
|
|
Description: "Topic or partition does not exist", Retriable: false,
|
|
},
|
|
ErrorCodeInvalidFetchSize: {
|
|
Code: ErrorCodeInvalidFetchSize, Name: "INVALID_FETCH_SIZE",
|
|
Description: "Invalid fetch size", Retriable: false,
|
|
},
|
|
ErrorCodeLeaderNotAvailable: {
|
|
Code: ErrorCodeLeaderNotAvailable, Name: "LEADER_NOT_AVAILABLE",
|
|
Description: "Leader not available", Retriable: true,
|
|
},
|
|
ErrorCodeNotLeaderOrFollower: {
|
|
Code: ErrorCodeNotLeaderOrFollower, Name: "NOT_LEADER_OR_FOLLOWER",
|
|
Description: "Not leader or follower", Retriable: true,
|
|
},
|
|
ErrorCodeRequestTimedOut: {
|
|
Code: ErrorCodeRequestTimedOut, Name: "REQUEST_TIMED_OUT",
|
|
Description: "Request timed out", Retriable: true,
|
|
},
|
|
ErrorCodeBrokerNotAvailable: {
|
|
Code: ErrorCodeBrokerNotAvailable, Name: "BROKER_NOT_AVAILABLE",
|
|
Description: "Broker not available", Retriable: true,
|
|
},
|
|
ErrorCodeMessageTooLarge: {
|
|
Code: ErrorCodeMessageTooLarge, Name: "MESSAGE_TOO_LARGE",
|
|
Description: "Message size exceeds limit", Retriable: false,
|
|
},
|
|
ErrorCodeOffsetMetadataTooLarge: {
|
|
Code: ErrorCodeOffsetMetadataTooLarge, Name: "OFFSET_METADATA_TOO_LARGE",
|
|
Description: "Offset metadata too large", Retriable: false,
|
|
},
|
|
ErrorCodeNetworkException: {
|
|
Code: ErrorCodeNetworkException, Name: "NETWORK_EXCEPTION",
|
|
Description: "Network error", Retriable: true,
|
|
},
|
|
ErrorCodeOffsetLoadInProgress: {
|
|
Code: ErrorCodeOffsetLoadInProgress, Name: "OFFSET_LOAD_IN_PROGRESS",
|
|
Description: "Offset load in progress", Retriable: true,
|
|
},
|
|
ErrorCodeNotCoordinatorForGroup: {
|
|
Code: ErrorCodeNotCoordinatorForGroup, Name: "NOT_COORDINATOR_FOR_GROUP",
|
|
Description: "Not coordinator for group", Retriable: true,
|
|
},
|
|
ErrorCodeInvalidGroupID: {
|
|
Code: ErrorCodeInvalidGroupID, Name: "INVALID_GROUP_ID",
|
|
Description: "Invalid group ID", Retriable: false,
|
|
},
|
|
ErrorCodeUnknownMemberID: {
|
|
Code: ErrorCodeUnknownMemberID, Name: "UNKNOWN_MEMBER_ID",
|
|
Description: "Unknown member ID", Retriable: false,
|
|
},
|
|
ErrorCodeInvalidSessionTimeout: {
|
|
Code: ErrorCodeInvalidSessionTimeout, Name: "INVALID_SESSION_TIMEOUT",
|
|
Description: "Invalid session timeout", Retriable: false,
|
|
},
|
|
ErrorCodeRebalanceInProgress: {
|
|
Code: ErrorCodeRebalanceInProgress, Name: "REBALANCE_IN_PROGRESS",
|
|
Description: "Group rebalance in progress", Retriable: true,
|
|
},
|
|
ErrorCodeInvalidCommitOffsetSize: {
|
|
Code: ErrorCodeInvalidCommitOffsetSize, Name: "INVALID_COMMIT_OFFSET_SIZE",
|
|
Description: "Invalid commit offset size", Retriable: false,
|
|
},
|
|
ErrorCodeTopicAuthorizationFailed: {
|
|
Code: ErrorCodeTopicAuthorizationFailed, Name: "TOPIC_AUTHORIZATION_FAILED",
|
|
Description: "Topic authorization failed", Retriable: false,
|
|
},
|
|
ErrorCodeGroupAuthorizationFailed: {
|
|
Code: ErrorCodeGroupAuthorizationFailed, Name: "GROUP_AUTHORIZATION_FAILED",
|
|
Description: "Group authorization failed", Retriable: false,
|
|
},
|
|
ErrorCodeUnsupportedVersion: {
|
|
Code: ErrorCodeUnsupportedVersion, Name: "UNSUPPORTED_VERSION",
|
|
Description: "Unsupported version", Retriable: false,
|
|
},
|
|
ErrorCodeTopicAlreadyExists: {
|
|
Code: ErrorCodeTopicAlreadyExists, Name: "TOPIC_ALREADY_EXISTS",
|
|
Description: "Topic already exists", Retriable: false,
|
|
},
|
|
ErrorCodeInvalidPartitions: {
|
|
Code: ErrorCodeInvalidPartitions, Name: "INVALID_PARTITIONS",
|
|
Description: "Invalid number of partitions", Retriable: false,
|
|
},
|
|
ErrorCodeInvalidReplicationFactor: {
|
|
Code: ErrorCodeInvalidReplicationFactor, Name: "INVALID_REPLICATION_FACTOR",
|
|
Description: "Invalid replication factor", Retriable: false,
|
|
},
|
|
ErrorCodeInvalidRecord: {
|
|
Code: ErrorCodeInvalidRecord, Name: "INVALID_RECORD",
|
|
Description: "Invalid record", Retriable: false,
|
|
},
|
|
ErrorCodeConnectionRefused: {
|
|
Code: ErrorCodeConnectionRefused, Name: "CONNECTION_REFUSED",
|
|
Description: "Connection refused", Retriable: true,
|
|
},
|
|
ErrorCodeConnectionTimeout: {
|
|
Code: ErrorCodeConnectionTimeout, Name: "CONNECTION_TIMEOUT",
|
|
Description: "Connection timeout", Retriable: true,
|
|
},
|
|
ErrorCodeReadTimeout: {
|
|
Code: ErrorCodeReadTimeout, Name: "READ_TIMEOUT",
|
|
Description: "Read operation timeout", Retriable: true,
|
|
},
|
|
ErrorCodeWriteTimeout: {
|
|
Code: ErrorCodeWriteTimeout, Name: "WRITE_TIMEOUT",
|
|
Description: "Write operation timeout", Retriable: true,
|
|
},
|
|
ErrorCodeIllegalGeneration: {
|
|
Code: ErrorCodeIllegalGeneration, Name: "ILLEGAL_GENERATION",
|
|
Description: "Illegal generation", Retriable: false,
|
|
},
|
|
ErrorCodeInconsistentGroupProtocol: {
|
|
Code: ErrorCodeInconsistentGroupProtocol, Name: "INCONSISTENT_GROUP_PROTOCOL",
|
|
Description: "Inconsistent group protocol", Retriable: false,
|
|
},
|
|
ErrorCodeMemberIDRequired: {
|
|
Code: ErrorCodeMemberIDRequired, Name: "MEMBER_ID_REQUIRED",
|
|
Description: "Member ID required", Retriable: false,
|
|
},
|
|
ErrorCodeFencedInstanceID: {
|
|
Code: ErrorCodeFencedInstanceID, Name: "FENCED_INSTANCE_ID",
|
|
Description: "Instance ID fenced", Retriable: false,
|
|
},
|
|
ErrorCodeGroupMaxSizeReached: {
|
|
Code: ErrorCodeGroupMaxSizeReached, Name: "GROUP_MAX_SIZE_REACHED",
|
|
Description: "Group max size reached", Retriable: false,
|
|
},
|
|
ErrorCodeUnstableOffsetCommit: {
|
|
Code: ErrorCodeUnstableOffsetCommit, Name: "UNSTABLE_OFFSET_COMMIT",
|
|
Description: "Offset commit during rebalance", Retriable: true,
|
|
},
|
|
}
|
|
|
|
// GetErrorInfo returns error information for the given error code
|
|
func GetErrorInfo(code int16) ErrorInfo {
|
|
if info, exists := KafkaErrors[code]; exists {
|
|
return info
|
|
}
|
|
return ErrorInfo{
|
|
Code: code, Name: "UNKNOWN", Description: "Unknown error code", Retriable: false,
|
|
}
|
|
}
|
|
|
|
// IsRetriableError returns true if the error is retriable
|
|
func IsRetriableError(code int16) bool {
|
|
return GetErrorInfo(code).Retriable
|
|
}
|
|
|
|
// BuildErrorResponse builds a standard Kafka error response (2-byte error code only).
|
|
// Prefer BuildAPIErrorResponse for API-aware error bodies.
|
|
func BuildErrorResponse(correlationID uint32, errorCode int16) []byte {
|
|
response := make([]byte, 0, 8)
|
|
|
|
// NOTE: Correlation ID is handled by writeResponseWithCorrelationID
|
|
// Do NOT include it in the response body
|
|
|
|
// Error code (2 bytes)
|
|
errorCodeBytes := make([]byte, 2)
|
|
binary.BigEndian.PutUint16(errorCodeBytes, uint16(errorCode))
|
|
response = append(response, errorCodeBytes...)
|
|
|
|
return response
|
|
}
|
|
|
|
// BuildAPIErrorResponse builds a minimal-but-valid error response body whose
|
|
// layout matches the schema the client expects for the given API key and
|
|
// version. The correlation ID and header-level tagged fields are NOT included
|
|
// (those are added by writeResponseWithHeader).
|
|
func BuildAPIErrorResponse(apiKey, apiVersion uint16, errorCode int16) []byte {
|
|
ec := make([]byte, 2)
|
|
binary.BigEndian.PutUint16(ec, uint16(errorCode))
|
|
throttle := []byte{0, 0, 0, 0} // throttle_time_ms = 0
|
|
emptyArr := []byte{0, 0, 0, 0} // regular array length = 0
|
|
nullStr := []byte{0xFF, 0xFF} // nullable string = null
|
|
emptyStr := []byte{0, 0} // string length = 0
|
|
|
|
switch APIKey(apiKey) {
|
|
|
|
// --- error_code is the first body field -----------------------------------
|
|
|
|
case APIKeyApiVersions:
|
|
// error_code(2) + api_keys_array + [throttle_time_ms v1+] [+ tagged_fields v3+]
|
|
buf := append([]byte{}, ec...)
|
|
if apiVersion >= 3 {
|
|
buf = append(buf, 1) // compact array length=0 (varint 1 = 0+1)
|
|
} else {
|
|
buf = append(buf, emptyArr...)
|
|
}
|
|
if apiVersion >= 1 {
|
|
buf = append(buf, throttle...)
|
|
}
|
|
if apiVersion >= 3 {
|
|
buf = append(buf, 0) // body-level tagged fields
|
|
}
|
|
return buf
|
|
|
|
// --- throttle_time_ms(4) + error_code(2) + trailing fields ----------------
|
|
|
|
case APIKeyFindCoordinator:
|
|
// [throttle v1+] + error_code + error_msg + node_id + host + port
|
|
buf := make([]byte, 0, 24)
|
|
if apiVersion >= 1 {
|
|
buf = append(buf, throttle...)
|
|
}
|
|
buf = append(buf, ec...)
|
|
buf = append(buf, nullStr...) // error_message
|
|
buf = append(buf, 0xFF, 0xFF, 0xFF, 0xFF) // node_id = -1
|
|
buf = append(buf, emptyStr...) // host
|
|
buf = append(buf, 0, 0, 0, 0) // port = 0
|
|
return buf
|
|
|
|
case APIKeyJoinGroup:
|
|
// [throttle v2+] + error_code + generation_id + protocol_name + leader + member_id + members[]
|
|
buf := make([]byte, 0, 24)
|
|
if apiVersion >= 2 {
|
|
buf = append(buf, throttle...)
|
|
}
|
|
buf = append(buf, ec...)
|
|
buf = append(buf, 0xFF, 0xFF, 0xFF, 0xFF) // generation_id = -1
|
|
buf = append(buf, nullStr...) // protocol_name
|
|
buf = append(buf, emptyStr...) // leader
|
|
buf = append(buf, emptyStr...) // member_id
|
|
buf = append(buf, emptyArr...) // members = []
|
|
return buf
|
|
|
|
case APIKeySyncGroup:
|
|
// [throttle v1+] + error_code + assignment
|
|
buf := make([]byte, 0, 12)
|
|
if apiVersion >= 1 {
|
|
buf = append(buf, throttle...)
|
|
}
|
|
buf = append(buf, ec...)
|
|
buf = append(buf, 0, 0, 0, 0) // assignment bytes length = 0
|
|
return buf
|
|
|
|
case APIKeyHeartbeat:
|
|
// [throttle v1+] + error_code
|
|
buf := make([]byte, 0, 8)
|
|
if apiVersion >= 1 {
|
|
buf = append(buf, throttle...)
|
|
}
|
|
buf = append(buf, ec...)
|
|
return buf
|
|
|
|
case APIKeyLeaveGroup:
|
|
// [throttle v1+] + error_code [+ members v3+]
|
|
buf := make([]byte, 0, 12)
|
|
if apiVersion >= 1 {
|
|
buf = append(buf, throttle...)
|
|
}
|
|
buf = append(buf, ec...)
|
|
if apiVersion >= 3 {
|
|
buf = append(buf, emptyArr...) // members = []
|
|
}
|
|
return buf
|
|
|
|
case APIKeyInitProducerId:
|
|
// throttle + error_code + producer_id + producer_epoch
|
|
buf := make([]byte, 0, 18)
|
|
buf = append(buf, throttle...)
|
|
buf = append(buf, ec...)
|
|
buf = append(buf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF) // producer_id = -1
|
|
buf = append(buf, 0xFF, 0xFF) // producer_epoch = -1
|
|
return buf
|
|
|
|
case APIKeyListGroups:
|
|
// [throttle v1+] + error_code + groups[]
|
|
buf := make([]byte, 0, 12)
|
|
if apiVersion >= 1 {
|
|
buf = append(buf, throttle...)
|
|
}
|
|
buf = append(buf, ec...)
|
|
buf = append(buf, emptyArr...) // groups = []
|
|
return buf
|
|
|
|
case APIKeyDescribeCluster:
|
|
// throttle + error_code + error_msg + cluster_id + controller_id + brokers[] + cluster_authorized_operations
|
|
buf := make([]byte, 0, 24)
|
|
buf = append(buf, throttle...)
|
|
buf = append(buf, ec...)
|
|
buf = append(buf, nullStr...) // error_message
|
|
buf = append(buf, emptyStr...) // cluster_id
|
|
buf = append(buf, 0xFF, 0xFF, 0xFF, 0xFF) // controller_id = -1
|
|
buf = append(buf, emptyArr...) // brokers = []
|
|
buf = append(buf, 0, 0, 0, 0) // cluster_authorized_operations
|
|
return buf
|
|
|
|
// --- array-based responses (no top-level error_code) ----------------------
|
|
|
|
case APIKeyProduce:
|
|
// topics[] + [throttle v1+]
|
|
buf := append([]byte{}, emptyArr...)
|
|
if apiVersion >= 1 {
|
|
buf = append(buf, throttle...)
|
|
}
|
|
return buf
|
|
|
|
case APIKeyFetch:
|
|
// [throttle v1+] [+ error_code + session_id v7+] + topics[]
|
|
buf := make([]byte, 0, 16)
|
|
if apiVersion >= 1 {
|
|
buf = append(buf, throttle...)
|
|
}
|
|
if apiVersion >= 7 {
|
|
buf = append(buf, ec...) // error_code
|
|
buf = append(buf, 0, 0, 0, 0) // session_id = 0
|
|
}
|
|
buf = append(buf, emptyArr...) // topics = []
|
|
return buf
|
|
|
|
case APIKeyMetadata:
|
|
// [throttle v3+] + brokers[] + [cluster_id v2+] + [controller_id v1+] + topics[]
|
|
buf := make([]byte, 0, 24)
|
|
if apiVersion >= 3 {
|
|
buf = append(buf, throttle...)
|
|
}
|
|
buf = append(buf, emptyArr...) // brokers = []
|
|
if apiVersion >= 2 {
|
|
buf = append(buf, nullStr...) // cluster_id
|
|
}
|
|
if apiVersion >= 1 {
|
|
buf = append(buf, 0xFF, 0xFF, 0xFF, 0xFF) // controller_id = -1
|
|
}
|
|
buf = append(buf, emptyArr...) // topics = []
|
|
return buf
|
|
|
|
case APIKeyListOffsets:
|
|
// [throttle v2+] + topics[]
|
|
buf := make([]byte, 0, 8)
|
|
if apiVersion >= 2 {
|
|
buf = append(buf, throttle...)
|
|
}
|
|
buf = append(buf, emptyArr...)
|
|
return buf
|
|
|
|
case APIKeyOffsetCommit:
|
|
// [throttle v3+] + topics[]
|
|
buf := make([]byte, 0, 8)
|
|
if apiVersion >= 3 {
|
|
buf = append(buf, throttle...)
|
|
}
|
|
buf = append(buf, emptyArr...)
|
|
return buf
|
|
|
|
case APIKeyOffsetFetch:
|
|
// [throttle v3+] + topics[] [+ error_code v2+]
|
|
buf := make([]byte, 0, 12)
|
|
if apiVersion >= 3 {
|
|
buf = append(buf, throttle...)
|
|
}
|
|
buf = append(buf, emptyArr...) // topics = []
|
|
if apiVersion >= 2 {
|
|
buf = append(buf, ec...) // error_code
|
|
}
|
|
return buf
|
|
|
|
case APIKeyCreateTopics:
|
|
// throttle + topics[]
|
|
buf := append([]byte{}, throttle...)
|
|
buf = append(buf, emptyArr...)
|
|
return buf
|
|
|
|
case APIKeyDeleteTopics:
|
|
// throttle + topics[]
|
|
buf := append([]byte{}, throttle...)
|
|
buf = append(buf, emptyArr...)
|
|
return buf
|
|
|
|
case APIKeyDescribeGroups:
|
|
// throttle + groups[]
|
|
buf := append([]byte{}, throttle...)
|
|
buf = append(buf, emptyArr...)
|
|
return buf
|
|
|
|
case APIKeyDescribeConfigs:
|
|
// throttle + resources[]
|
|
buf := append([]byte{}, throttle...)
|
|
buf = append(buf, emptyArr...)
|
|
return buf
|
|
|
|
default:
|
|
// Unknown API — emit just the error code as a best-effort fallback
|
|
return append([]byte{}, ec...)
|
|
}
|
|
}
|
|
|
|
// BuildErrorResponseWithMessage builds a Kafka error response with error message
|
|
func BuildErrorResponseWithMessage(correlationID uint32, errorCode int16, message string) []byte {
|
|
response := BuildErrorResponse(correlationID, errorCode)
|
|
|
|
// Error message (2 bytes length + message)
|
|
if message == "" {
|
|
response = append(response, 0xFF, 0xFF) // Null string
|
|
} else {
|
|
messageLen := uint16(len(message))
|
|
messageLenBytes := make([]byte, 2)
|
|
binary.BigEndian.PutUint16(messageLenBytes, messageLen)
|
|
response = append(response, messageLenBytes...)
|
|
response = append(response, []byte(message)...)
|
|
}
|
|
|
|
return response
|
|
}
|
|
|
|
// ClassifyNetworkError classifies network errors into appropriate Kafka error codes
|
|
func ClassifyNetworkError(err error) int16 {
|
|
if err == nil {
|
|
return ErrorCodeNone
|
|
}
|
|
|
|
// Check for network errors
|
|
if netErr, ok := err.(net.Error); ok {
|
|
if netErr.Timeout() {
|
|
return ErrorCodeRequestTimedOut
|
|
}
|
|
return ErrorCodeNetworkException
|
|
}
|
|
|
|
// Check for specific error types
|
|
switch err.Error() {
|
|
case "connection refused":
|
|
return ErrorCodeConnectionRefused
|
|
case "connection timeout":
|
|
return ErrorCodeConnectionTimeout
|
|
default:
|
|
return ErrorCodeUnknownServerError
|
|
}
|
|
}
|
|
|
|
// TimeoutConfig holds timeout configuration for connections and operations
|
|
type TimeoutConfig struct {
|
|
ConnectionTimeout time.Duration // Timeout for establishing connections
|
|
ReadTimeout time.Duration // Timeout for read operations
|
|
WriteTimeout time.Duration // Timeout for write operations
|
|
RequestTimeout time.Duration // Overall request timeout
|
|
}
|
|
|
|
// DefaultTimeoutConfig returns default timeout configuration
|
|
func DefaultTimeoutConfig() TimeoutConfig {
|
|
return TimeoutConfig{
|
|
ConnectionTimeout: 30 * time.Second,
|
|
ReadTimeout: 10 * time.Second,
|
|
WriteTimeout: 10 * time.Second,
|
|
RequestTimeout: 30 * time.Second,
|
|
}
|
|
}
|
|
|
|
// HandleTimeoutError handles timeout errors and returns appropriate error code
|
|
func HandleTimeoutError(err error, operation string) int16 {
|
|
if err == nil {
|
|
return ErrorCodeNone
|
|
}
|
|
|
|
// Handle context timeout errors
|
|
if err == context.DeadlineExceeded {
|
|
switch operation {
|
|
case "read":
|
|
return ErrorCodeReadTimeout
|
|
case "write":
|
|
return ErrorCodeWriteTimeout
|
|
case "connect":
|
|
return ErrorCodeConnectionTimeout
|
|
default:
|
|
return ErrorCodeRequestTimedOut
|
|
}
|
|
}
|
|
|
|
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
|
|
switch operation {
|
|
case "read":
|
|
return ErrorCodeReadTimeout
|
|
case "write":
|
|
return ErrorCodeWriteTimeout
|
|
case "connect":
|
|
return ErrorCodeConnectionTimeout
|
|
default:
|
|
return ErrorCodeRequestTimedOut
|
|
}
|
|
}
|
|
|
|
return ClassifyNetworkError(err)
|
|
}
|