@@ -6,6 +6,7 @@ use crate::{
6
6
} ;
7
7
use anyhow:: { bail, Context } ;
8
8
use bytes:: { BufMut , Bytes , BytesMut } ;
9
+ use futures:: TryFutureExt ;
9
10
use kafka_protocol:: {
10
11
error:: { ParseResponseErrorCode , ResponseError } ,
11
12
messages:: {
@@ -1103,13 +1104,21 @@ impl Session {
1103
1104
#[ instrument( skip_all, fields( group=?req. group_id) ) ]
1104
1105
pub async fn offset_commit (
1105
1106
& mut self ,
1106
- req : messages:: OffsetCommitRequest ,
1107
+ mut req : messages:: OffsetCommitRequest ,
1107
1108
header : RequestHeader ,
1108
1109
) -> anyhow:: Result < messages:: OffsetCommitResponse > {
1109
- let mut mutated_req = req. clone ( ) ;
1110
- for topic in & mut mutated_req. topics {
1110
+ let collection_partitions = self
1111
+ . fetch_collection_partitions ( req. topics . iter ( ) . map ( |topic| & topic. name ) )
1112
+ . await ?
1113
+ . into_iter ( )
1114
+ . map ( |( topic_name, partitions) | {
1115
+ self . encrypt_topic_name ( topic_name)
1116
+ . map ( |encrypted_name| ( encrypted_name, partitions) )
1117
+ } )
1118
+ . collect :: < Result < Vec < _ > , _ > > ( ) ?;
1119
+
1120
+ for topic in & mut req. topics {
1111
1121
let encrypted = self . encrypt_topic_name ( topic. name . clone ( ) ) ?;
1112
- tracing:: info!( topic_name = ?topic. name, partitions = ?topic. partitions, "Committing offset" ) ;
1113
1122
topic. name = encrypted;
1114
1123
}
1115
1124
@@ -1119,17 +1128,9 @@ impl Session {
1119
1128
. connect_to_group_coordinator ( req. group_id . as_str ( ) )
1120
1129
. await ?;
1121
1130
1122
- client
1123
- . ensure_topics (
1124
- mutated_req
1125
- . topics
1126
- . iter ( )
1127
- . map ( |t| t. name . to_owned ( ) )
1128
- . collect ( ) ,
1129
- )
1130
- . await ?;
1131
+ client. ensure_topics ( collection_partitions) . await ?;
1131
1132
1132
- let mut resp = client. send_request ( mutated_req , Some ( header) ) . await ?;
1133
+ let mut resp = client. send_request ( req . clone ( ) , Some ( header) ) . await ?;
1133
1134
1134
1135
let auth = self
1135
1136
. auth
@@ -1142,48 +1143,65 @@ impl Session {
1142
1143
let auth = self . auth . as_ref ( ) . unwrap ( ) ;
1143
1144
1144
1145
for topic in resp. topics . iter_mut ( ) {
1145
- topic. name = self . decrypt_topic_name ( topic. name . to_owned ( ) ) ?;
1146
+ let encrypted_name = topic. name . clone ( ) ;
1147
+ let decrypted_name = self . decrypt_topic_name ( topic. name . to_owned ( ) ) ?;
1146
1148
1147
1149
let collection_partitions = Collection :: new (
1148
1150
& self . app ,
1149
1151
auth,
1150
1152
& flow_client. pg_client ( ) ,
1151
- topic . name . as_str ( ) ,
1153
+ decrypted_name . as_str ( ) ,
1152
1154
)
1153
1155
. await ?
1154
1156
. context ( format ! ( "unable to look up partitions for {:?}" , topic. name) ) ?
1155
1157
. partitions ;
1156
1158
1157
1159
for partition in & topic. partitions {
1158
1160
if let Some ( error) = partition. error_code . err ( ) {
1159
- tracing:: warn!( topic=?topic. name, partition=partition. partition_index, ?error, "Got error from upstream Kafka when trying to commit offsets" ) ;
1161
+ tracing:: warn!(
1162
+ topic = decrypted_name. as_str( ) ,
1163
+ partition = partition. partition_index,
1164
+ ?error,
1165
+ "Got error from upstream Kafka when trying to commit offsets"
1166
+ ) ;
1160
1167
} else {
1161
1168
let journal_name = collection_partitions
1162
1169
. get ( partition. partition_index as usize )
1163
1170
. context ( format ! (
1164
- "unable to find partition {} in collection {:?}" ,
1165
- partition. partition_index, topic. name
1171
+ "unable to find collection partition idx {} in collection {:?}" ,
1172
+ partition. partition_index,
1173
+ decrypted_name. as_str( )
1166
1174
) ) ?
1167
1175
. spec
1168
1176
. name
1169
1177
. to_owned ( ) ;
1170
1178
1171
- let committed_offset = req
1179
+ let partitions = & req
1172
1180
. topics
1173
1181
. iter ( )
1174
- . find ( |req_topic| req_topic. name == topic. name )
1175
- . context ( format ! ( "unable to find topic in request {:?}" , topic. name) ) ?
1176
- . partitions
1182
+ . find ( |req_topic| req_topic. name == encrypted_name)
1183
+ . context ( format ! (
1184
+ "unable to find topic in request {:?}" ,
1185
+ decrypted_name. as_str( )
1186
+ ) ) ?
1187
+ . partitions ;
1188
+
1189
+ let committed_offset = partitions
1177
1190
. get ( partition. partition_index as usize )
1178
1191
. context ( format ! (
1179
- "unable to find partition {}" ,
1180
- partition. partition_index
1192
+ "unable to find topic partition idx {} in topic {:?}. It has: {:?}. Flow has: {:?}" ,
1193
+ partition. partition_index,
1194
+ decrypted_name. as_str( ) ,
1195
+ partitions,
1196
+ collection_partitions
1181
1197
) ) ?
1182
1198
. committed_offset ;
1183
1199
1184
1200
metrics:: gauge!( "dekaf_committed_offset" , "group_id" =>req. group_id. to_string( ) , "journal_name" =>journal_name) . set ( committed_offset as f64 ) ;
1185
1201
}
1186
1202
}
1203
+
1204
+ tracing:: info!( topic_name = ?topic. name, partitions = ?topic. partitions, "Committed offset" ) ;
1187
1205
}
1188
1206
1189
1207
Ok ( resp)
@@ -1192,11 +1210,23 @@ impl Session {
1192
1210
#[ instrument( skip_all, fields( group=?req. group_id) ) ]
1193
1211
pub async fn offset_fetch (
1194
1212
& mut self ,
1195
- req : messages:: OffsetFetchRequest ,
1213
+ mut req : messages:: OffsetFetchRequest ,
1196
1214
header : RequestHeader ,
1197
1215
) -> anyhow:: Result < messages:: OffsetFetchResponse > {
1198
- let mut mutated_req = req. clone ( ) ;
1199
- if let Some ( ref mut topics) = mutated_req. topics {
1216
+ let collection_partitions = if let Some ( topics) = & req. topics {
1217
+ self . fetch_collection_partitions ( topics. iter ( ) . map ( |topic| & topic. name ) )
1218
+ . await ?
1219
+ . into_iter ( )
1220
+ . map ( |( topic_name, partitions) | {
1221
+ self . encrypt_topic_name ( topic_name)
1222
+ . map ( |encrypted_name| ( encrypted_name, partitions) )
1223
+ } )
1224
+ . collect :: < Result < Vec < _ > , _ > > ( ) ?
1225
+ } else {
1226
+ vec ! [ ]
1227
+ } ;
1228
+
1229
+ if let Some ( ref mut topics) = req. topics {
1200
1230
for topic in topics {
1201
1231
topic. name = self . encrypt_topic_name ( topic. name . clone ( ) ) ?;
1202
1232
}
@@ -1208,12 +1238,11 @@ impl Session {
1208
1238
. connect_to_group_coordinator ( req. group_id . as_str ( ) )
1209
1239
. await ?;
1210
1240
1211
- if let Some ( ref topics) = mutated_req. topics {
1212
- client
1213
- . ensure_topics ( topics. iter ( ) . map ( |t| t. name . to_owned ( ) ) . collect ( ) )
1214
- . await ?;
1241
+ if !collection_partitions. is_empty ( ) {
1242
+ client. ensure_topics ( collection_partitions) . await ?;
1215
1243
}
1216
- let mut resp = client. send_request ( mutated_req, Some ( header) ) . await ?;
1244
+
1245
+ let mut resp = client. send_request ( req, Some ( header) ) . await ?;
1217
1246
1218
1247
for topic in resp. topics . iter_mut ( ) {
1219
1248
topic. name = self . decrypt_topic_name ( topic. name . to_owned ( ) ) ?;
@@ -1318,6 +1347,30 @@ impl Session {
1318
1347
}
1319
1348
}
1320
1349
1350
+ async fn fetch_collection_partitions (
1351
+ & mut self ,
1352
+ topics : impl IntoIterator < Item = & TopicName > ,
1353
+ ) -> anyhow:: Result < Vec < ( TopicName , usize ) > > {
1354
+ let auth = self
1355
+ . auth
1356
+ . as_mut ( )
1357
+ . ok_or ( anyhow:: anyhow!( "Session not authenticated" ) ) ?;
1358
+
1359
+ let app = & self . app ;
1360
+ let flow_client = & auth. flow_client ( app) . await ?. pg_client ( ) ;
1361
+
1362
+ // Re-declare here to drop mutable reference
1363
+ let auth = self . auth . as_ref ( ) . unwrap ( ) ;
1364
+
1365
+ futures:: future:: try_join_all ( topics. into_iter ( ) . map ( |topic| async move {
1366
+ let collection = Collection :: new ( app, auth, flow_client, topic. as_ref ( ) )
1367
+ . await ?
1368
+ . context ( format ! ( "unable to look up partitions for {:?}" , topic) ) ?;
1369
+ Ok :: < ( TopicName , usize ) , anyhow:: Error > ( ( topic. clone ( ) , collection. partitions . len ( ) ) )
1370
+ } ) )
1371
+ . await
1372
+ }
1373
+
1321
1374
/// If the fetched offset is within a fixed number of offsets from the end of the journal,
1322
1375
/// return Some with a PartitionOffset containing the beginning and end of the latest fragment.
1323
1376
#[ tracing:: instrument( skip( self ) ) ]
0 commit comments