github.com/streamdal/segmentio-kafka-go@v0.4.47-streamdal/protocol/produce/produce.go (about) 1 package produce 2 3 import ( 4 "fmt" 5 6 "github.com/segmentio/kafka-go/protocol" 7 ) 8 9 func init() { 10 protocol.Register(&Request{}, &Response{}) 11 } 12 13 type Request struct { 14 TransactionalID string `kafka:"min=v3,max=v8,nullable"` 15 Acks int16 `kafka:"min=v0,max=v8"` 16 Timeout int32 `kafka:"min=v0,max=v8"` 17 Topics []RequestTopic `kafka:"min=v0,max=v8"` 18 } 19 20 func (r *Request) ApiKey() protocol.ApiKey { return protocol.Produce } 21 22 func (r *Request) Broker(cluster protocol.Cluster) (protocol.Broker, error) { 23 broker := protocol.Broker{ID: -1} 24 25 for i := range r.Topics { 26 t := &r.Topics[i] 27 28 topic, ok := cluster.Topics[t.Topic] 29 if !ok { 30 return broker, NewError(protocol.NewErrNoTopic(t.Topic)) 31 } 32 33 for j := range t.Partitions { 34 p := &t.Partitions[j] 35 36 partition, ok := topic.Partitions[p.Partition] 37 if !ok { 38 return broker, NewError(protocol.NewErrNoPartition(t.Topic, p.Partition)) 39 } 40 41 if b, ok := cluster.Brokers[partition.Leader]; !ok { 42 return broker, NewError(protocol.NewErrNoLeader(t.Topic, p.Partition)) 43 } else if broker.ID < 0 { 44 broker = b 45 } else if b.ID != broker.ID { 46 return broker, NewError(fmt.Errorf("mismatching leaders (%d!=%d)", b.ID, broker.ID)) 47 } 48 } 49 } 50 51 return broker, nil 52 } 53 54 func (r *Request) Prepare(apiVersion int16) { 55 // Determine which version of the message should be used, based on which 56 // version of the Produce API is supported by the server. 57 // 58 // In version 0.11, kafka gives this error: 59 // 60 // org.apache.kafka.common.record.InvalidRecordException 61 // Produce requests with version 3 are only allowed to contain record batches with magic version. 62 // 63 // In version 2.x, kafka refuses the message claiming that the CRC32 64 // checksum is invalid. 65 var recordVersion int8 66 67 if apiVersion < 3 { 68 recordVersion = 1 69 } else { 70 recordVersion = 2 71 } 72 73 for i := range r.Topics { 74 t := &r.Topics[i] 75 76 for j := range t.Partitions { 77 p := &t.Partitions[j] 78 79 // Allow the program to overload the version if really needed. 80 if p.RecordSet.Version == 0 { 81 p.RecordSet.Version = recordVersion 82 } 83 } 84 } 85 } 86 87 func (r *Request) HasResponse() bool { 88 return r.Acks != 0 89 } 90 91 type RequestTopic struct { 92 Topic string `kafka:"min=v0,max=v8"` 93 Partitions []RequestPartition `kafka:"min=v0,max=v8"` 94 } 95 96 type RequestPartition struct { 97 Partition int32 `kafka:"min=v0,max=v8"` 98 RecordSet protocol.RecordSet `kafka:"min=v0,max=v8"` 99 } 100 101 type Response struct { 102 Topics []ResponseTopic `kafka:"min=v0,max=v8"` 103 ThrottleTimeMs int32 `kafka:"min=v1,max=v8"` 104 } 105 106 func (r *Response) ApiKey() protocol.ApiKey { return protocol.Produce } 107 108 type ResponseTopic struct { 109 Topic string `kafka:"min=v0,max=v8"` 110 Partitions []ResponsePartition `kafka:"min=v0,max=v8"` 111 } 112 113 type ResponsePartition struct { 114 Partition int32 `kafka:"min=v0,max=v8"` 115 ErrorCode int16 `kafka:"min=v0,max=v8"` 116 BaseOffset int64 `kafka:"min=v0,max=v8"` 117 LogAppendTime int64 `kafka:"min=v2,max=v8"` 118 LogStartOffset int64 `kafka:"min=v5,max=v8"` 119 RecordErrors []ResponseError `kafka:"min=v8,max=v8"` 120 ErrorMessage string `kafka:"min=v8,max=v8,nullable"` 121 } 122 123 type ResponseError struct { 124 BatchIndex int32 `kafka:"min=v8,max=v8"` 125 BatchIndexErrorMessage string `kafka:"min=v8,max=v8,nullable"` 126 } 127 128 var ( 129 _ protocol.BrokerMessage = (*Request)(nil) 130 _ protocol.PreparedMessage = (*Request)(nil) 131 ) 132 133 type Error struct { 134 Err error 135 } 136 137 func NewError(err error) *Error { 138 return &Error{Err: err} 139 } 140 141 func (e *Error) Error() string { 142 return fmt.Sprintf("fetch request error: %v", e.Err) 143 } 144 145 func (e *Error) Unwrap() error { 146 return e.Err 147 }