docs: def connect_job(job_id,
                  deployment_name,
                  token_manager=None,
                  app_url=defaults.APP_URL,
                  persist=False,
                  websocket=None,
                  data_url=None):
      """
      connect to a running Juttle program by job_id
  
      """
  
      if data_url == None:
          data_url = get_data_url_for_job(job_id,
                                          deployment_name,
                                          token_manager=token_manager,
                                          app_url=app_url)
  
      if websocket == None:
          websocket = __wss_connect(data_url,
                                    token_manager,
                                    job_id=job_id)
  
      pong = json.dumps({
          'pong': True
      })
  
      if not persist:
          job_finished = False
  
          while not job_finished:
              try:
                  data = websocket.recv()
  
                  if data:
                      payload = json.loads(data)
  
                      if is_debug_enabled():
                          printable_payload = dict(payload)
                          if 'points' in payload:
                              # don't want to print out all the outputs when in
                              # debug mode
                              del printable_payload['points']
                              printable_payload['points'] = 'NOT SHOWN'
  
                          debug('received %s' % json.dumps(printable_payload))
  
                      if 'ping' in payload.keys():
                          # ping/pong (ie heartbeat) mechanism
                          websocket.send(pong)
  
                          if is_debug_enabled():
                              debug('sent %s' % json.dumps(pong))
  
                      if 'job_end' in payload.keys() and payload['job_end'] == True:
                          job_finished = True
  
                      if token_manager.is_access_token_expired():
                          debug('refreshing access token')
                          token_obj = {
                              "accessToken": token_manager.get_access_token()
                          }
                          # refresh authentication token
                          websocket.send(json.dumps(token_obj))
  
                      if 'error' in payload:
                          if payload['error'] == 'NONEXISTENT-JOB':
                              raise JutException('Job "%s" no longer running' % job_id)
  
                      # return all channel messages
                      yield payload
  
                  else:
                      debug('payload was "%s", forcing websocket reconnect' % data)
                      raise IOError()
  
              except IOError:
                  if is_debug_enabled():
                      traceback.print_exc()
                  #
                  # We'll retry for just under 30s since internally we stop
                  # running non persistent programs after 30s of not heartbeating
                  # with the client
                  #
                  retry = 1
                  while retry <= 5:
                      try:
                          debug('network error reconnecting to job %s, '
                                'try %s of 5' % (job_id, retry))
                          websocket = __wss_connect(data_url, token_manager, job_id=job_id)
                          break
  
                      except socket.error:
  
                          if is_debug_enabled():
                              traceback.print_exc()
  
                          retry += 1
                          time.sleep(5)
  
                  debug('network error reconnecting to job %s, '
                        'try %s of 5' % (job_id, retry))
                  websocket = __wss_connect(data_url, token_manager, job_id=job_id)
  
      websocket.close()