class_docstr: Class for clusters following a master-worker architecture.
  
  Usually you want to inherit from this class and do not want to use it directly. It is recommended to treat this
  class as an abstract class or an interface.
  
  Examples:
      Create a cluster with all `Runtimes` detected by the `RuntimeManager`.
  
      ```python
      from lazycluster import RuntimeManager
      cluster = MyMasterWorkerClusterImpl(RuntimeManager().create_group())
      cluster.start()
      ```
  
      Use different strategies for launching the master and the worker instance as the default ones by providing
      custom implementation of `MasterLauncher` and `WorkerLauncher`.
  
      ```python
      cluster = MyMasterWorkerClusterImpl(RuntimeManager().create_group(),
                                          MyMasterLauncherImpl(),
                                          MyWorkerLauncherImpl()
      cluster.start()
      ```
class_docstr_tok: ["Class","for","clusters","following","a","master-worker","architecture",".","Usually","you","want","to","inherit","from","this","class","and","do","not","want","to","use","it","directly",".","It","is","recommended","to","treat","this","class","as","an","abstract","class","or","an","interface",".","Examples",":","Create","a","cluster","with","all","`","Runtimes","`","detected","by","the","`","RuntimeManager","`",".","``","`","python","from","lazycluster","import","RuntimeManager","cluster","=","MyMasterWorkerClusterImpl","(","RuntimeManager","(",")",".create_group","(",")",")","cluster.start","(",")","``","`","Use","different","strategies","for","launching","the","master","and","the","worker","instance","as","the","default","ones","by","providing","custom","implementation","of","`","MasterLauncher","`","and","`","WorkerLauncher","`",".","``","`","python","cluster","=","MyMasterWorkerClusterImpl","(","RuntimeManager","(",")",".create_group","(",")",",","MyMasterLauncherImpl","(",")",",","MyWorkerLauncherImpl","(",")","cluster.start","(",")","``","`"]
docstr: Start the master instance.
  
  Note:
      How the master is actually started is determined by the the actual `MasterLauncher` implementation. Another
      implementation adhering to the `MasterLauncher` interface can be provided in the constructor of the cluster
      class.
  
  Args:
      master_port: Port of the master instance. Defaults to `self.DEFAULT_MASTER_PORT`, but another one is chosen if
                   the port is not free within the group. The actual chosen port can be requested via
                   self.master_port.
      timeout: Timeout (s) after which an MasterStartError is raised if master instance not started yet.
      debug: If `True`, stdout/stderr from the runtime will be printed to stdout of localhost. Has no effect for
             if the master instance is started locally, what default MasterLauncher implementations usually do.
  
  Raises:
      PortInUseError: If a single port is given and it is not free in the `RuntimeGroup`.
      NoPortsLeftError: If there are no free ports left in the port list for instantiating the master.
      MasterStartError: If master was not started after the specified `timeout`.
docstr_tok: ["Start","the","master","instance",".","Note",":","How","the","master","is","actually","started","is","determined","by","the","the","actual","`","MasterLauncher","`","implementation",".","Another","implementation","adhering","to","the","`","MasterLauncher","`","interface","can","be","provided","in","the","constructor","of","the","cluster","class",".","Args",":","master_port",":","Port","of","the","master","instance",".","Defaults","to","`","self.DEFAULT_MASTER_PORT","`",",","but","another","one","is","chosen","if","the","port","is","not","free","within","the","group",".","The","actual","chosen","port","can","be","requested","via","self.master_port",".","timeout",":","Timeout","(","s",")","after","which","an","MasterStartError","is","raised","if","master","instance","not","started","yet",".","debug",":","If","`","True","`",",","stdout\/stderr","from","the","runtime","will","be","printed","to","stdout","of","localhost",".","Has","no","effect","for","if","the","master","instance","is","started","locally",",","what","default","MasterLauncher","implementations","usually","do",".","Raises",":","PortInUseError",":","If","a","single","port","is","given","and","it","is","not","free","in","the","`","RuntimeGroup","`",".","NoPortsLeftError",":","If","there","are","no","free","ports","left","in","the","port","list","for","instantiating","the","master",".","MasterStartError",":","If","master","was","not","started","after","the","specified","`","timeout","`","."]
code: def start_master(
      self,
      master_port: Optional[int] = None,
      timeout: int = 3,
      debug: bool = False,
  ) -> None:
      """Start the master instance.
  
      Note:
          How the master is actually started is determined by the the actual `MasterLauncher` implementation. Another
          implementation adhering to the `MasterLauncher` interface can be provided in the constructor of the cluster
          class.
  
      Args:
          master_port: Port of the master instance. Defaults to `self.DEFAULT_MASTER_PORT`, but another one is chosen if
                       the port is not free within the group. The actual chosen port can be requested via
                       self.master_port.
          timeout: Timeout (s) after which an MasterStartError is raised if master instance not started yet.
          debug: If `True`, stdout/stderr from the runtime will be printed to stdout of localhost. Has no effect for
                 if the master instance is started locally, what default MasterLauncher implementations usually do.
  
      Raises:
          PortInUseError: If a single port is given and it is not free in the `RuntimeGroup`.
          NoPortsLeftError: If there are no free ports left in the port list for instantiating the master.
          MasterStartError: If master was not started after the specified `timeout`.
      """
      if not self._master_launcher:
          raise LazyclusterError("Master Launcher does not exist.")
  
      # 1. Determine a port or port list
      overwrite_port_list = False
      if master_port:
          ports: Union[int, List[int]] = master_port
      elif self._group.has_free_port(self.DEFAULT_MASTER_PORT):
          ports = self.DEFAULT_MASTER_PORT
      else:
          ports = self._ports
          overwrite_port_list = True
  
      # 2. Trigger the actual logic for starting the master instance
      ports = self._master_launcher.start(
          ports, timeout, debug
      )  # Raises the possible exceptions
  
      if overwrite_port_list:
          self._ports = ports
  
      # Some attributes must be set in the given MasterLauncher implementation after
      # starting the master to ensure correct behavior of MasterWorkerCluster
      # => indicates a wrong implementation of the given launcher class
      assert self._master_launcher.port
      if not self._master_launcher.process:
          self.log.debug(
              "No self._master_launcher.process is set after starting the cluster master. If the master"
              "instance was not started as a deamon, then this could indicate buggy implementation. The"
              "variable should be set to be able to eventually shutdown the cluster."
          )
  
      self.log.info(
          f"Master instance started on port {str(self.master_port)}."
      )
  
imports: import atexit
  import logging
  from subprocess import Popen
  from typing import Dict, List, Optional, Union
  from lazycluster.exceptions import LazyclusterError
  from lazycluster.runtime_mgmt import RuntimeGroup
label_desc: Use image node_id 6 for calling the MasterWorkerCluster obj's underlying member method code with example usage: obj.start_master(master_port, timeout, debug) without return types