class_docstr: This is where tuners and assessors are not defined yet.
  Inherits this class to make your own advisor.
  
  .. note::
  
      The class inheriting MsgDispatcherBase should be instantiated
      after nnimanager (rest server) is started, so that the object
      is ready to use right after its instantiation.
class_docstr_tok: ["This","is","where","tuners","and","assessors","are","not","defined","yet",".","Inherits","this","class","to","make","your","own","advisor",".","..","note",":",":","The","class","inheriting","MsgDispatcherBase","should","be","instantiated","after","nnimanager","(","rest","server",")","is","started",",","so","that","the","object","is","ready","to","use","right","after","its","instantiation","."]
code: def __init__(self, command_channel_url=None):
      super().__init__()
      self.stopping = False
      if command_channel_url is None:
          command_channel_url = (
              dispatcher_env_vars.NNI_TUNER_COMMAND_CHANNEL
          )
      self._channel = TunerCommandChannel(command_channel_url)
      # NOTE: `connect()` should be put in __init__. First, this `connect()` affects nnimanager's
      # starting process, without `connect()` nnimanager is blocked in `dispatcher.init()`.
      # Second, nas experiment uses a thread to execute `run()` of this class, thus, there is
      # no way to know when the websocket between nnimanager and dispatcher is built. The following
      # logic may crash is websocket is not built. One example is updating search space. If updating
      # search space too soon, as the websocket has not been built, the rest api of updating search
      # space will timeout.
      # FIXME: this is making unittest happy
      if not command_channel_url.startswith("ws://_unittest_"):
          self._channel.connect()
      self.default_command_queue = Queue()
      self.assessor_command_queue = Queue()
      # here daemon should be True, because their parent thread is configured as daemon to enable smooth exit of NAS experiment.
      # if daemon is not set, these threads will block the daemon effect of their parent thread.
      self.default_worker = threading.Thread(
          target=self.command_queue_worker,
          args=(self.default_command_queue,),
          daemon=True,
      )
      self.assessor_worker = threading.Thread(
          target=self.command_queue_worker,
          args=(self.assessor_command_queue,),
          daemon=True,
      )
      self.worker_exceptions = []
  
imports: import threading
  import logging
  from queue import Queue, Empty
  from .env_vars import dispatcher_env_vars
  from ..common import load
  from ..recoverable import Recoverable
  from .tuner_command_channel import CommandType, TunerCommandChannel
label_desc: Use image node_id 1 to create a new MsgDispatcherBase object from inherited base classes: Recoverable with example: obj = MsgDispatcherBase(command_channel_url)