title: How to handle various failure conditions in Kafka
body: <h2> Issue we were facing:</h2>
  
  <p>In our system we were logging a ticket in database with status <code>NEW</code> and also putting it in the kafka queue for further processing. The processors pick those tickets from kafka queue, do processing and update the status accordingly. We found that some tickets are left in <code>NEW</code> state forever. So we were guessing whether tickets are failing to get produced in the queue or are no getting consumed.</p>
  
  <p><br /></p>
  
  <h2> Message loss / duplication scenarios (and some other related points):</h2>
  
  <p>So I started to dig exhaustively to know in what all ways we can face message loss and duplication in Kafka. Below I have listed all possible message loss and duplication scenarios that I can find in <a href="https://sookocheff.com/post/kafka/kafka-in-a-nutshell#consistency-and-availability" rel="noreferrer">this post</a>:</p>
  
  <blockquote>
    <ol>
    <li><strong>How data loss can occur in different approaches to handle all replicas down</strong> 
    
    <ol>
    <li><strong>Handle by waiting for leader to come online</strong><br>
     Messages sent between all replica down and leader comes online are lost. </li>
    <li><strong>Handle by electing new broker as a leader once it comes online</strong><br>
     If new broker is out of sync from previous leader, all data written between the 
     time where this broker went down and when it was elected the new leader will be 
     lost. As additional brokers come back up, they will see that they have committed 
     messages that do not exist on the new leader and drop those messages. </li>
    </ol></li>
    <li><p><strong>How data loss can occur when leader goes down, while other replicas may be up</strong><br>
    In this case, the Kafka controller will detect the loss of the leader and elect a new leader from the pool of in sync replicas. This may take a few seconds and result in LeaderNotAvailable errors from the client. However, no data loss will occur as long as producers and consumers handle this possibility and retry appropriately.</p></li>
    <li><p><strong>When a consumer may miss to consume a message</strong><br>
    If Kafka is configured to keep messages for a day and a consumer is down for a period of longer than a day, the consumer will lose messages. </p></li>
    <li><p><strong>Evaluating different approaches to consumer consistency</strong> </p>
    
    <ol>
    <li>Message might not be processed when consumer is configured to receive each message at most once </li>
    <li>Message might be duplicated / processed twice when consumer is configured to receive each message at least once </li>
    <li>No message is processed multiple times or left unprocessed if consumer is configured to receive each message exactly once. </li>
    </ol></li>
    <li><p>Kafka provides below guarantees as long as you are producing to one partition and consuming from one partition. All guarantees are off if you are reading from the same partition using two consumers or writing to the same partition using two producers. 
    Kafka makes the following guarantees about data consistency and availability:  </p>
    
    <ol>
    <li>Messages sent to a topic partition will be appended to the commit log in the order they are sent,  </li>
    <li>a single consumer instance will see messages in the order they appear in the log,  </li>
    <li>a message is ‘committed’ when all in sync replicas have applied it to their log, and </li>
    <li>any committed message will not be lost, as long as at least one in sync replica is alive. </li>
    </ol></li>
    </ol>
  </blockquote>
  
  <p><br /></p>
  
  <h2> Approach I came up with: </h2>
  
  <p>After reading several articles, I felt I should do following:</p>
  
  <blockquote>
    <ol>
    <li><p><strong>If message is not enqueued, producer should resend</strong><br>
    For this producer should listen for acknowledgement for each message sent. If no ackowledement is received, it can retry sending message </p></li>
    <li><p><strong>Producer should be async with callback:</strong><br>
    As explained in <a href="https://www.learningjournal.guru/courses/kafka/kafka-foundation-training/callback-and-acks/" rel="noreferrer">last example here</a> </p></li>
    <li><p><strong>How to avoid duplicates in case of producer retries sending</strong><br>
    To avoid duplicates in queue, set <code>enable.idempotence=true</code> in producer configs. This will make producer ensure that exactly one copy of each message is sent. This requires following properties set on producer: </p>
    
    <ul>
    <li><code>max.in.flight.requests.per.connection</code>&lt;=5 </li>
    <li><code>retries</code>>0 </li>
    <li><code>acks=all</code> (Obtain ack when all brokers has committed message) </li>
    </ul></li>
    <li><p><strong>Producer should be transactional</strong><br>
    As explained <a href="https://www.baeldung.com/kafka-exactly-once" rel="noreferrer">here</a>. </p>
    
    <ul>
    <li><p><strong>Set transactional id to unique id:</strong>  </p>
  
  <pre><code> producerProps.put("transactional.id", "prod-1"); 
  </code></pre>
    
    <p>Because we've enabled <code>idempotence</code>, Kafka will use this transaction id as part of its algorithm to deduplicate any message this producer sends, ensuring idempotency.  </p></li>
    <li><p><strong>Use transactions semantics: init, begin, commit, close</strong><br>
    As explained <a href="https://www.confluent.io/blog/exactly-once-semantics-are-possible-heres-how-apache-kafka-does-it/" rel="noreferrer">here</a>: </p>
  
  <pre><code>producer.initTransactions(); 
  try { 
      producer.beginTransaction(); 
      producer.send(record1); 
      producer.send(record2); 
      producer.commitTransaction(); 
  } catch(ProducerFencedException e) { 
      producer.close(); 
  } catch(KafkaException e) { 
      producer.abortTransaction(); 
  } 
  </code></pre></li>
    </ul></li>
    <li><p><strong>Consumer should be transactional</strong>   </p>
  
  <pre><code>  consumerProps.put("isolation.level", "read_committed"); 
  </code></pre>
    
    <p>This ensures that consumer don't read any transactional messages before the transaction completes. </p></li>
    <li><p><strong>Manually commit offset in consumer</strong><br>
    As explained <a href="https://www.learningjournal.guru/courses/kafka/kafka-foundation-training/exactly-once-processing/" rel="noreferrer">here</a></p>
    
    <ul>
    <li><p><strong>Process record and save offsets atomically</strong><br>
    Say by atomically saving both record processing output and offsets to any database. For this we need to set auto commit of database connection to false and manually commit after persisting both processing output and offset. This also requires setting <code>enable.auto.commit</code> to <code>false</code>.</p></li>
    <li><p><strong>Read initial offset (say to read after recovery from cache) from database</strong><br>
    Seek consumer to this offset and then read from that position. </p></li>
    </ul></li>
    </ol>
  </blockquote>
  
  <p><br /></p>
  
  <h2> Doubts I have: </h2>
  
  <p>(Some doubts might be primary and can be resolved by implementing code. But I want words from experienced kafka developer.)</p>
  
  <ol>
  <li><p>Does the consumer need to read the offset from database only for initial (/ first after consumer recovery) read or for all reads? I feel it needs to read offset from database only on restarts, as explained <a href="https://medium.com/@jaykreps/exactly-once-support-in-apache-kafka-55e1fdd0a35f" rel="noreferrer">here</a> </p></li>
  <li><p>Do we have to opt for manual partitioning? Does this approach works only with auto partitioning off? I have this doubt because <a href="https://www.learningjournal.guru/courses/kafka/kafka-foundation-training/callback-and-acks/" rel="noreferrer">this example</a> explains storing offset in MySQL by specifying partitions explicitly. </p></li>
  <li><p>Do we need both: Producer side kafka transactions and consumer side database transactions (for storing offset and processing records atomically)? I feel for producer idempotence, we need producer to have unique transaction id and for that we need to use kafka transactional api (init, begin, commit). And as a counterpart, consumer also need to set <code>isolation.level</code> to <code>read_committed</code>. However can we ensure no message loss and duplicate processing without using kafka transactions? Or they are absolutely necessary?</p></li>
  <li><p>Should we persist offset to external db as explained above and <a href="https://www.learningjournal.guru/courses/kafka/kafka-foundation-training/exactly-once-processing/" rel="noreferrer">here</a><br>
  <strong>or</strong> send offset to transaction as explained <a href="https://www.baeldung.com/kafka-exactly-once" rel="noreferrer">here</a>  (also I didnt get what does it exactly mean by sending offset to transaction)
  <strong>or</strong> follow sync async commit combo explained <a href="https://www.learningjournal.guru/courses/kafka/kafka-foundation-training/offset-management/" rel="noreferrer">here</a>.  </p></li>
  <li><p>I feel message loss / duplication scenarios 1 and 2 are handled by points 1 to 4 of approach I explained above.</p></li>
  <li><p>I feel message loss / duplication scenario 3 is handled by point 6 of approach I explained above.</p></li>
  <li><p>How do we implement different consumer consistency approaches as stated in message loss / duplication scenario 4? Is their any configuration or it needs to be implemented inside custom logic inside consumer?</p></li>
  <li><p>Message loss / duplication scenario 5 says: "Kafka provides below guarantees as long as you are producing to one partition and consuming from one partition."? Is it something to concern about while building correct system? </p></li>
  <li><p>Is any consideration unnecessary/redundant in the approach I came up with above? Also did I miss any necessary consideration? Did I miss any message loss / duplication scenarios? </p></li>
  <li><p>Is their any other standard / recommended / preferable approach to ensure no message loss and duplicate processing than what I have thought above? </p></li>
  <li><p>Do I have to actually code above approach using kafka APIs? or is there any high level API built atop kafka API which allows to easily ensure no message loss and duplicate processing?</p></li>
  <li><p>Looking at issue we were facing (as stated at very beginning), we were thinking if we can recover any lost/unprocessed messages from files in which kafka stores messages. However that isnt correct, right?</p></li>
  </ol>
  
  <p>(Extremely sorry for such an exhaustive post but wanted to write question which will ask all related question at one place allowing to build big picture of how to build system around kafka.)</p>