class_docstr: Shipper reads structured logs from logq and ships them to the determined-master.
  
  It will send a message on doneq when it finishes.
code: def ship(self, data: bytes, backoffs: List[int]) -> None:
      for delay in backoffs:
          time.sleep(delay)
          try:
              req = urllib.request.Request(
                  self.logs_url, data, self.headers, method="POST"
              )
              try:
                  with urllib.request.urlopen(
                      req, context=self.context
                  ) as resp:
                      respbody = resp.read()
              except urllib.error.URLError as e:
                  # urllib stacktraces are awful, so see if we can interpret what happened.
                  # Note that we've already connected successfully to the master so failures here
                  # are likely related to master crashing or the network breaking or something to
                  # that effect.
                  if isinstance(e, urllib.error.HTTPError):
                      raise RuntimeError(
                          f"POST logs returned status code: {e.code} and reason: {e.reason}, "
                          "is the master healthy?"
                      ) from None
                  elif isinstance(e.reason, ConnectionRefusedError):
                      raise RuntimeError(
                          "The connection to {self.master_url} was refused, is master down?"
                      )
                  raise
  
              if resp.getcode() != 200:
                  raise RuntimeError(
                      f"ship logs failed: status code {resp.get_code()}, body:\n---\n"
                      + respbody.decode("utf8")
                  )
  
              # Shipped successfully
              return
  
          except Exception:
              logging.error(
                  "failed to ship logs to master", exc_info=True
              )
  
      raise RuntimeError(
          "failed to connect to master for too long, giving up"
      )
  
imports: import datetime
  import io
  import json
  import logging
  import os
  import queue
  import re
  import signal
  import socket
  import ssl
  import subprocess
  import sys
  import threading
  import time
  import traceback
  import urllib.error
  import urllib.request
  from typing import Any, Dict, Iterator, List, NamedTuple, Optional, cast
label_desc: Use image node_id 4 for calling the Shipper obj's underlying member method code with example usage: obj.ship(data, backoffs) without return types