def run_tasks_in_background(
    tasks: Mapping[str, Callable[[], _T]],
    *,
    timeout: float | None = None,
    max_workers: int | None = None,
) -> tuple[Mapping[str, _T], Mapping[str, BaseException]]:
  """Runs the callables in parallel, blocks until all complete.

  IMPORTANT: Passed callables must be threadsafe.

  Args:
    tasks: callables to execute (MUST BE THREADSAFE)
    timeout: the maximum number of seconds to wait.
    max_workers: them maximum number of parallel jobs. If None will use as many
      workers as there are tasks.

  Returns:
    (results, errors): a mappings from key to the result of the callable or the
    exception it raised. Thus if no task raised an error, errors will be empty.
  """
  results = {}
  errors = {}
  try:
    for key, future in _as_completed(
        tasks, timeout=timeout, max_workers=max_workers
    ):
      error = future.exception()
      if error is not None:
        errors[key] = error
      else:
        results[key] = future.result()
  except TimeoutError as error:
    unfinished = tasks.keys() - results.keys() - errors.keys()
    for key in unfinished:
      errors[key] = error
  return results, errors
Runs the callables in parallel, blocks until all complete.

  IMPORTANT: Passed callables must be threadsafe.

  Args:
    tasks: callables to execute (MUST BE THREADSAFE)
    timeout: the maximum number of seconds to wait.
    max_workers: them maximum number of parallel jobs. If None will use as many
      workers as there are tasks.

  Returns:
    (results, errors): a mappings from key to the result of the callable or the
    exception it raised. Thus if no task raised an error, errors will be empty.
  
concordia/utils/concurrency.py