@@ -311,13 +311,13 @@ handle_info({msg, Conn, Rsp}, #{conn := Conn} = St0) ->
311311 St = maybe_send_to_kafka (St1 ),
312312 {noreply , St }
313313 catch
314- throw : Reason ->
314+ throw : { kafka_error , Reason , St1 } ->
315315 % % connection is not really down, but we need to
316316 % % stay down for a while and maybe restart sending on a new connection
317317 % % if Reason is not_leader_for_partition,
318318 % % wolff_client should expire old metadata while we are down
319319 % % and connect to the new leader when we request for a new connection
320- St = mark_connection_down (St0 , Reason ),
320+ St = mark_connection_down (St1 , Reason ),
321321 {noreply , St }
322322 end ;
323323handle_info (? leader_connection (Conn ), St ) ->
@@ -423,13 +423,13 @@ use_defaults(Config, [{K, V} | Rest]) ->
423423 false -> use_defaults (Config #{K => V }, Rest )
424424 end .
425425
426- remake_requests (#{q_items := Items , attempts : = Attempts } = Sent , St , ? reconnect ) ->
426+ remake_requests (#{q_items := Items } = Sent , St , ? reconnect ) ->
427427 # kpro_req {ref = Ref } = Req = make_request (Items , St ),
428- {[Req ], [Sent #{req_ref := Ref , attempts : = Attempts + 1 }]};
428+ {[Req ], [Sent #{req_ref := Ref }]};
429429remake_requests (#{q_items := Items } = Sent , St , ? message_too_large ) ->
430430 Reqs = lists :map (fun (Item ) -> make_request ([Item ], St ) end , Items ),
431431 #{attempts := Attempts , q_ack_ref := Q_AckRef } = Sent ,
432- {Reqs , make_sent_items_list (Items , Reqs , Attempts + 1 , Q_AckRef )}.
432+ {Reqs , make_sent_items_list (Items , Reqs , Attempts , Q_AckRef )}.
433433
434434% % only ack replayq when the last message is accepted by Kafka
435435make_sent_items_list ([LastItem ], [# kpro_req {ref = Ref }], Attempts , Q_AckRef ) ->
@@ -528,13 +528,13 @@ send_to_kafka(#{sent_reqs := SentReqs,
528528 pending_acks := NewPendingAcks
529529 },
530530 ok = request_async (Conn , Req ),
531- St2 = maybe_fake_kafka_ack (NoAck , Sent , St1 ),
531+ St2 = maybe_fake_kafka_ack (NoAck , St1 ),
532532 maybe_send_to_kafka (St2 ).
533533
534534% % when require no acks do not add to sent_reqs and ack caller immediately
535- maybe_fake_kafka_ack (_NoAck = true , Sent , St ) ->
536- do_handle_kafka_ack (? no_error , ? UNKNOWN_OFFSET , Sent , St );
537- maybe_fake_kafka_ack (_NoAck , _Sent , St ) -> St .
535+ maybe_fake_kafka_ack (_NoAck = true , St ) ->
536+ do_handle_kafka_ack (? no_error , ? UNKNOWN_OFFSET , St );
537+ maybe_fake_kafka_ack (_NoAck , St ) -> St .
538538
539539is_send_ahead_allowed (#{config := #{max_send_ahead := Max },
540540 sent_reqs_count := SentCount }) ->
@@ -603,9 +603,9 @@ handle_kafka_ack(#kpro_rsp{api = produce,
603603 ErrorCode = kpro :find (error_code , PartitionRsp ),
604604 BaseOffset = kpro :find (base_offset , PartitionRsp ),
605605 case queue :peek (SentReqs ) of
606- {value , #{req_ref := Ref } = Sent } ->
606+ {value , #{req_ref := Ref1 }} when Ref1 =:= Ref ->
607607 % % sent_reqs queue front matched the response reference
608- do_handle_kafka_ack (ErrorCode , BaseOffset , Sent , St );
608+ do_handle_kafka_ack (ErrorCode , BaseOffset , St );
609609 _ ->
610610 % % stale response e.g. when inflight > 1, but we have to retry an older req
611611 St
@@ -614,12 +614,12 @@ handle_kafka_ack(#kpro_rsp{api = produce,
614614note (Fmt , Args ) ->
615615 lists :flatten (io_lib :format (Fmt , Args )).
616616
617- -spec do_handle_kafka_ack (_ , _ , sent (), state ()) -> state ().
618- do_handle_kafka_ack (? no_error , BaseOffset , _Sent , St ) ->
617+ -spec do_handle_kafka_ack (_ , _ , state ()) -> state ().
618+ do_handle_kafka_ack (? no_error , BaseOffset , St ) ->
619619 clear_sent_and_ack_callers (? no_error , BaseOffset , St );
620- do_handle_kafka_ack (EC , _BaseOffset , Sent , St ) when EC =:= ? message_too_large orelse EC =:= ? record_list_too_large ->
621- #{topic := Topic , partition := Partition , config := Config } = St ,
622- #{q_items := Items } = Sent ,
620+ do_handle_kafka_ack (EC , _BaseOffset , St ) when EC =:= ? message_too_large orelse EC =:= ? record_list_too_large ->
621+ #{topic := Topic , partition := Partition , config := Config , sent_reqs : = SentReqs } = St ,
622+ { value , #{q_items := Items }} = queue : peek ( SentReqs ) ,
623623 # kpro_req {msg = IoData } = make_request (Items , St ),
624624 Bytes = iolist_size (IoData ),
625625 Hint = case EC of
@@ -649,11 +649,14 @@ do_handle_kafka_ack(EC, _BaseOffset, Sent, St) when EC =:= ?message_too_large or
649649 " Will use max_batch_bytes=~p to collect future batches. " ++ Hint ,
650650 [Max , NewMax ]),
651651 log_warn (Topic , Partition , EC , #{note => Note , calls_count => N , encode_bytes => Bytes }),
652+ % % We do not incement the attempt counter for too large batch
653+ % % St2 = increment_attempt_for_first_sent_req(St),
652654 resend_sent_reqs (St1 , Reason )
653655 end ;
654- do_handle_kafka_ack (ErrorCode , _BaseOffset , Sent , St ) ->
656+ do_handle_kafka_ack (ErrorCode , _BaseOffset , St ) ->
655657 % % Other errors, such as not_leader_for_partition
656- #{attempts := Attempts , q_items := Items } = Sent ,
658+ #{sent_reqs := SentReqs } = St ,
659+ {value , #{attempts := Attempts , q_items := Items }} = queue :peek (SentReqs ),
657660 #{topic := Topic ,
658661 partition := Partition ,
659662 config := Config
@@ -664,7 +667,15 @@ do_handle_kafka_ack(ErrorCode, _BaseOffset, Sent, St) ->
664667 #{error_code => ErrorCode ,
665668 batch_size => count_msgs (Items ),
666669 attempts => Attempts }),
667- erlang :throw (ErrorCode ).
670+ St1 = increment_attempt (St ),
671+ erlang :throw ({kafka_error , ErrorCode , St1 }).
672+
673+ % % Since we only handle Kafka ack for the first sent request in the sent queue
674+ % % we only bump the first itme with attempt counter
675+ increment_attempt (#{sent_reqs := SentReqs } = St ) ->
676+ {{value , SentReq }, SentReqs1 } = queue :out (SentReqs ),
677+ #{attempts := Attempts } = SentReq ,
678+ St #{sent_reqs := queue :in_r (SentReq #{attempts := Attempts + 1 }, SentReqs1 )}.
668679
669680clear_sent_and_ack_callers (ErrorCode , BaseOffset , St ) ->
670681 #{sent_reqs := SentReqs ,
@@ -1020,11 +1031,10 @@ reply_error_for_all_reqs(St, Reason) ->
10201031 end ,
10211032 Count = wolff_pendack :fold (PendingAcks , F , 0 ),
10221033 AlreadyInc = lists :foldl (
1023- fun (#{attempts := 1 }, Acc ) ->
1024- % % sent but not yet acked
1034+ fun (#{attempts := Attempts }, Acc ) when Attempts > 1 ->
1035+ % % 'failed' counter is already incremented for this sent request
10251036 Acc + 1 ;
10261037 (_ , Acc ) ->
1027- % % sent and acked with error, the failed count is already incremented
10281038 Acc
10291039 end , 0 , queue :to_list (SentReqs )),
10301040 inc_sent_failed (Config , Count - AlreadyInc , 1 ).
0 commit comments