def download(self, bundle_uuid, replica, version="", download_dir="",
                 metadata_files=('*',), data_files=('*',),
                 num_retries=10, min_delay_seconds=0.25):
        errors = 0
        with concurrent.futures.ThreadPoolExecutor(self.threads) as executor:
            futures_to_dss_file = {executor.submit(task): dss_file
                                   for dss_file, task in self._download_tasks(bundle_uuid,
                                                                              replica,
                                                                              version,
                                                                              download_dir,
                                                                              metadata_files,
                                                                              data_files,
                                                                              num_retries,
                                                                              min_delay_seconds)}
            for future in concurrent.futures.as_completed(futures_to_dss_file):
                dss_file = futures_to_dss_file[future]
                try:
                    future.result()
                except Exception as e:
                    errors += 1
                    logger.warning('Failed to download file %s version %s from replica %s',
                                   dss_file.uuid, dss_file.version, dss_file.replica, exc_info=e)
        if errors:
            raise RuntimeError('{} file(s) failed to download'.format(errors))