docs: def attach(self, buffer, read_line=None):
          """
          Read buffer until end (read() returns '') and sends it to self.logger and self.job_backend.
  
          :param buffer: a buffer instance with block read() or readline() method
          :param read_line: callable or True to read line per line. If callable is given, it will be executed per line
                            and ignores does not redirect the line to stdout/logger when callable returns False.
          """
  
          bid = id(buffer)
          self.attach_last_messages[bid] = b''
  
          def reader():
              current_line = b''
  
              def handle_line(buf):
                  if chunk == b'':
                      return
  
                  if read_line and callable(read_line):
                      res = read_line(buf)
                      if res is False:
                          return False
  
                      elif res is not None:
                          buf = res
                          if hasattr(buf, 'encode'):
                              buf = buf.encode('utf-8')
  
                  self.attach_last_messages[bid] += buf
  
                  if len(self.attach_last_messages[bid]) > 21 * 1024:
                      self.attach_last_messages[bid] = self.attach_last_messages[bid][-20 * 1024:]
  
                  self.write(buf)
  
              flush_char = b'\n'
  
              while True:
                  try:
                      # needs to be 1 so we fetch data in near real-time
                      chunk = buffer.read(1)
                      if chunk == b'':
                          if current_line:
                              handle_line(current_line)
                          return
  
                      current_line += chunk
  
                      while flush_char in current_line:
                          pos = current_line.find(flush_char)
                          line = current_line[:pos+1]
                          current_line = current_line[pos+1:]
                          handle_line(line)
  
                      # todo, periodically flush by '\r' only (progress bars for example)
                      # and make sure only necessary data is sent (by applying \r and \b control characters)
  
                  except (KeyboardInterrupt, SystemExit):
                      raise
                  except Exception:
                      # we need to make sure, we continue to read otherwise the process of this buffer
                      # will block and we have a stuck process.
                      sys.__stderr__.write(traceback.format_exc() + '\n')
                      sys.__stderr__.flush()
  
          thread = Thread(target=reader)
          thread.daemon = True
          thread.start()
  
          def wait():
              thread_join_non_blocking(thread)
              self.send_buffer()
  
          return wait