@@ -11,7 +11,7 @@ import (
11
11
"go.uber.org/zap"
12
12
)
13
13
14
- func (s * Service ) ConsumeFromManagementTopic (ctx context.Context ) error {
14
+ func (s * Service ) startConsumeMessages (ctx context.Context ) {
15
15
client := s .client
16
16
topicName := s .config .TopicManagement .Name
17
17
topic := kgo .ConsumeTopics (kgo .NewOffset ().AtEnd (), topicName )
@@ -33,81 +33,73 @@ func (s *Service) ConsumeFromManagementTopic(ctx context.Context) error {
33
33
for {
34
34
select {
35
35
case <- ctx .Done ():
36
- return nil
36
+ return
37
37
default :
38
38
fetches := client .PollFetches (ctx )
39
+ receiveTimestamp := time .Now ()
40
+
41
+ // Log all errors and continue afterwards as we might get errors and still have some fetch results
39
42
errors := fetches .Errors ()
40
43
for _ , err := range errors {
41
- // Log all errors and continue afterwards as we might get errors and still have some fetch results
42
44
s .logger .Error ("kafka fetch error" ,
43
45
zap .String ("topic" , err .Topic ),
44
46
zap .Int32 ("partition" , err .Partition ),
45
47
zap .Error (err .Err ))
46
48
}
47
49
48
- receiveTimestampMs := timeNowMs ()
49
-
50
- //
51
50
// Process messages
52
- iter := fetches .RecordIter ()
53
- var record * kgo.Record
54
- for ! iter .Done () {
55
- record = iter .Next ()
56
-
57
- if record == nil {
58
- continue
51
+ fetches .EachRecord (func (record * kgo.Record ) {
52
+ if record != nil {
53
+ s .processMessage (record , receiveTimestamp )
59
54
}
55
+ })
56
+ }
57
+ }
58
+ }
60
59
61
- s . processMessage ( record , receiveTimestampMs )
62
- }
60
+ func ( s * Service ) commitOffsets ( ctx context. Context ) {
61
+ client := s . client
63
62
64
- //
65
- // Commit offsets for processed messages
66
- // todo: the normal way to commit offsets with franz-go is pretty good, but in our special case
67
- // we want to do it manually, seperately for each partition, so we can track how long it took
68
- if uncommittedOffset := client .UncommittedOffsets (); uncommittedOffset != nil {
63
+ //
64
+ // Commit offsets for processed messages
65
+ // todo: the normal way to commit offsets with franz-go is pretty good, but in our special case
66
+ // we want to do it manually, seperately for each partition, so we can track how long it took
67
+ if uncommittedOffset := client .UncommittedOffsets (); uncommittedOffset != nil {
69
68
70
- startCommitTimestamp := timeNowMs ()
69
+ startCommitTimestamp := time . Now ()
71
70
72
- client .CommitOffsets (ctx , uncommittedOffset , func (req * kmsg.OffsetCommitRequest , r * kmsg.OffsetCommitResponse , err error ) {
73
- // got commit response
71
+ client .CommitOffsets (ctx , uncommittedOffset , func (req * kmsg.OffsetCommitRequest , r * kmsg.OffsetCommitResponse , err error ) {
72
+ // got commit response
73
+ latency := time .Since (startCommitTimestamp )
74
74
75
- latencyMs := timeNowMs () - startCommitTimestamp
76
- commitLatency := time .Duration (latencyMs * float64 (time .Millisecond ))
75
+ if err != nil {
76
+ s .logger .Error ("offset commit failed" , zap .Error (err ), zap .Int64 ("latencyMilliseconds" , latency .Milliseconds ()))
77
+ return
78
+ }
77
79
80
+ for _ , t := range r .Topics {
81
+ for _ , p := range t .Partitions {
82
+ err := kerr .ErrorForCode (p .ErrorCode )
78
83
if err != nil {
79
- s .logger .Error ("offset commit failed" , zap .Error (err ), zap .Int64 ("latencyMilliseconds" , commitLatency .Milliseconds ()))
80
- return
81
- }
82
-
83
- for _ , t := range r .Topics {
84
- for _ , p := range t .Partitions {
85
- err := kerr .ErrorForCode (p .ErrorCode )
86
- if err != nil {
87
- s .logger .Error ("error committing partition offset" , zap .String ("topic" , t .Topic ), zap .Int32 ("partitionId" , p .Partition ), zap .Error (err ))
88
- }
89
- }
90
- }
91
-
92
- // only report commit latency if the coordinator wasn't set too long ago
93
- if time .Since (s .clientHooks .lastCoordinatorUpdate ) < 10 * time .Second {
94
- coordinator := s .clientHooks .currentCoordinator .Load ().(kgo.BrokerMetadata )
95
- s .onOffsetCommit (coordinator .NodeID , commitLatency )
84
+ s .logger .Error ("error committing partition offset" , zap .String ("topic" , t .Topic ), zap .Int32 ("partitionId" , p .Partition ), zap .Error (err ))
96
85
}
97
- })
86
+ }
98
87
}
99
88
100
- }
89
+ // only report commit latency if the coordinator wasn't set too long ago
90
+ if time .Since (s .clientHooks .lastCoordinatorUpdate ) < 10 * time .Second {
91
+ coordinator := s .clientHooks .currentCoordinator .Load ().(kgo.BrokerMetadata )
92
+ s .onOffsetCommit (coordinator .NodeID , latency )
93
+ }
94
+ })
101
95
}
102
-
103
96
}
104
97
105
- // todo: then also create a "tracker" that knows about in-flight messages, and the latest successful roundtrips
106
-
107
- // processMessage takes a message and:
108
- // - checks if it matches minionID and latency
109
- // - updates metrics accordingly
110
- func (s * Service ) processMessage (record * kgo.Record , receiveTimestampMs float64 ) {
98
+ // processMessage:
99
+ // - deserializes the message
100
+ // - checks if it is from us, or from another kminion process running somewhere else
101
+ // - hands it off to the service, which then reports metrics on it
102
+ func (s * Service ) processMessage (record * kgo.Record , receiveTimestamp time.Time ) {
111
103
var msg EndToEndMessage
112
104
if jerr := json .Unmarshal (record .Value , & msg ); jerr != nil {
113
105
return // maybe older version
@@ -117,7 +109,14 @@ func (s *Service) processMessage(record *kgo.Record, receiveTimestampMs float64)
117
109
return // not from us
118
110
}
119
111
120
- latency := time .Duration ((receiveTimestampMs - msg .Timestamp ) * float64 (time .Millisecond ))
112
+ // restore partition, which was not serialized
113
+ msg .partition = int (record .Partition )
114
+
115
+ created := msg .creationTime ()
116
+ latency := receiveTimestamp .Sub (created )
121
117
122
118
s .onRoundtrip (record .Partition , latency )
119
+
120
+ // notify the tracker that the message arrived
121
+ s .messageTracker .onMessageArrived (& msg )
123
122
}
0 commit comments