docs: def append(self, offset, timestamp, key, value, headers,
                 # Cache for LOAD_FAST opcodes
                 encode_varint=encode_varint, size_of_varint=size_of_varint,
                 get_type=type, type_int=int, time_time=time.time,
                 byte_like=(bytes, bytearray, memoryview),
                 bytearray_type=bytearray, len_func=len, zero_len_varint=1
                 ):
          """ Write message to messageset buffer with MsgVersion 2
          """
          # Check types
          if get_type(offset) != type_int:
              raise TypeError(offset)
          if timestamp is None:
              timestamp = type_int(time_time() * 1000)
          elif get_type(timestamp) != type_int:
              raise TypeError(timestamp)
          if not (key is None or get_type(key) in byte_like):
              raise TypeError(
                  "Not supported type for key: {}".format(type(key)))
          if not (value is None or get_type(value) in byte_like):
              raise TypeError(
                  "Not supported type for value: {}".format(type(value)))
  
          # We will always add the first message, so those will be set
          if self._first_timestamp is None:
              self._first_timestamp = timestamp
              self._max_timestamp = timestamp
              timestamp_delta = 0
              first_message = 1
          else:
              timestamp_delta = timestamp - self._first_timestamp
              first_message = 0
  
          # We can't write record right away to out buffer, we need to
          # precompute the length as first value...
          message_buffer = bytearray_type(b"\x00")  # Attributes
          write_byte = message_buffer.append
          write = message_buffer.extend
  
          encode_varint(timestamp_delta, write_byte)
          # Base offset is always 0 on Produce
          encode_varint(offset, write_byte)
  
          if key is not None:
              encode_varint(len_func(key), write_byte)
              write(key)
          else:
              write_byte(zero_len_varint)
  
          if value is not None:
              encode_varint(len_func(value), write_byte)
              write(value)
          else:
              write_byte(zero_len_varint)
  
          encode_varint(len_func(headers), write_byte)
  
          for h_key, h_value in headers:
              h_key = h_key.encode("utf-8")
              encode_varint(len_func(h_key), write_byte)
              write(h_key)
              if h_value is not None:
                  encode_varint(len_func(h_value), write_byte)
                  write(h_value)
              else:
                  write_byte(zero_len_varint)
  
          message_len = len_func(message_buffer)
          main_buffer = self._buffer
  
          required_size = message_len + size_of_varint(message_len)
          # Check if we can write this message
          if (required_size + len_func(main_buffer) > self._batch_size and
                  not first_message):
              return None
  
          # Those should be updated after the length check
          if self._max_timestamp < timestamp:
              self._max_timestamp = timestamp
          self._num_records += 1
          self._last_offset = offset
  
          encode_varint(message_len, main_buffer.append)
          main_buffer.extend(message_buffer)
  
          return DefaultRecordMetadata(offset, required_size, timestamp)