@@ -282,6 +282,10 @@ def run_import(self):
282282 # Allow for two open file descriptors per download:
283283 # The temporary download file that the file is streamed to initially, and then
284284 # the actual destination file that it is moved to.
285+ # Note that with the possibility of a chunked file download,
286+ # the true number of file descriptors used may be higher,
287+ # but this is unlikely to be a problem in practice, and we build in extra tolerance
288+ # in the fd_safe_executor max worker calculation.
285289 with fd_safe_executor (fds_per_task = 2 ) as executor :
286290 self .executor = executor
287291 batch_size = 100
@@ -392,8 +396,27 @@ def __init__(
392396 )
393397
394398 self .session = requests .Session ()
399+ # Because we create the executor in the run method, we need to track
400+ # we need to mount the adapter in the create_file_transfer method
401+ # so that we can introspect the executor to configure the pool correctly.
402+ self ._adapter_mounted = False
403+
404+ def _mount_adapter (self ):
405+ if not self ._adapter_mounted :
406+ # If we are using a ThreadPoolExecutor, then we need to make sure
407+ # that the requests session has enough connections to handle
408+ # the number of threads.
409+ max_workers = self .executor ._max_workers
410+ adapter = requests .adapters .HTTPAdapter (
411+ pool_connections = max_workers ,
412+ pool_maxsize = max_workers ,
413+ )
414+ self .session .mount ("http://" , adapter )
415+ self .session .mount ("https://" , adapter )
416+ self ._adapter_mounted = True
395417
396418 def create_file_transfer (self , f , filename , dest ):
419+ self ._mount_adapter ()
397420 url = paths .get_content_storage_remote_url (filename , baseurl = self .baseurl )
398421 return transfer .FileDownload (
399422 url ,
0 commit comments