docstr: Run a pipe or service group job.
  
  This lets all items run simultaneously.
code: def run_group_job(self, job: GroupJobExecutorInterface):
      """Run a pipe or service group job.
  
      This lets all items run simultaneously."""
      # we only have to consider pipe or service groups because in local running mode,
      # these are the only groups that will occur
  
      service_futures = [
          self.run_single_job(j) for j in job if j.is_service
      ]
      normal_futures = [
          self.run_single_job(j) for j in job if not j.is_service
      ]
  
      while normal_futures:
          for f in list(normal_futures):
              if f.done():
                  logger.debug("Job inside group is finished.")
                  ex = f.exception()
                  if ex is not None:
                      logger.debug(
                          f"Job inside group failed with exception {ex}."
                      )
                      # kill all shell commands of the other group jobs
                      # there can be only shell commands because the
                      # run directive is not allowed for pipe jobs
                      for j in job:
                          shell.kill(j.jobid)
                      raise ex
                  normal_futures.remove(f)
          time.sleep(1)
  
      if service_futures:
          # terminate all service jobs since all consumers are done
          for j in job:
              if j.is_service:
                  logger.info(
                      f"Terminating service job {j.jobid} since all consuming jobs are finished."
                  )
                  shell.terminate(j.jobid)
                  logger.info(
                      f"Service job {j.jobid} has been successfully terminated."
                  )
  
imports: import os
  from pathlib import Path
  import sys
  import time
  import shlex
  import concurrent.futures
  import subprocess
  from functools import partial
  from snakemake.common import async_run
  from snakemake.executors import change_working_directory
  from snakemake.settings import DeploymentMethod
  from snakemake_interface_executor_plugins.executors.base import SubmittedJobInfo
  from snakemake_interface_executor_plugins.executors.real import RealExecutor
  from snakemake_interface_executor_plugins.dag import DAGExecutorInterface
  from snakemake_interface_executor_plugins.workflow import WorkflowExecutorInterface
  from snakemake_interface_executor_plugins.logging import LoggerExecutorInterface
  from snakemake_interface_executor_plugins.jobs import JobExecutorInterface, SingleJobExecutorInterface, GroupJobExecutorInterface
  from snakemake_interface_executor_plugins.settings import ExecMode, CommonSettings
  from snakemake.shell import shell
  from snakemake.logging import logger
  from snakemake.exceptions import print_exception, get_exception_origin
  from snakemake.exceptions import format_error, RuleException, log_verbose_traceback
  from snakemake.exceptions import WorkflowError, SpawnedJobError, CacheMissException
label_desc: Use image node_id 11 for calling the Executor obj's underlying member method code with example usage: obj.run_group_job(job) without return types