Ответ 1
Короткий ответ на вопрос: запросы будут закрывать соединение в случае любого исключения, включая KeyboardInterrupt
и SystemExit
.
Немного рытья в запросах исходного кода показывает, что requests.get
в конечном счете вызывает HTTPAdapter.send
метод (который является, где все происходит волшебство).
Есть два способа, с помощью которых запрос мог быть сделан в методе send
: chunked или not chunked. Которая send
мы выполняем, зависит от значения request.body
и заголовка Content-Length
:
chunked = not (request.body is None or 'Content-Length' in request.headers)
В случае, когда тело запроса равно None
или Content-Length
установлено, requests
будут использовать высокоуровневый urlopen
метод urllib3
:
if not chunked:
resp = conn.urlopen(
method=request.method,
url=url,
body=request.body,
# ...
)
finally
, блок urllib3.PoolManager.urlopen
методы имеет код, который обрабатывает закрытие соединения в случае, когда try
блок не выполнить успешно:
clean_exit = False
# ...
try:
# ...
# Everything went great!
clean_exit = True
finally:
if not clean_exit:
# We hit some kind of exception, handled or otherwise. We need
# to throw the connection away unless explicitly told not to.
# Close the connection, set the variable to None, and make sure
# we put the None back in the pool to avoid leaking it.
conn = conn and conn.close()
release_this_conn = True
В случае, когда ответ может быть помечен, запросы идут немного ниже уровня и использует базовое соединение низкого уровня, предоставляемое urllib3
. В этом случае запросы все еще обрабатывают исключение, он делает это с помощью блока try
/except
который начинается сразу после захвата соединения и заканчивается:
low_conn = conn._get_conn(timeout=DEFAULT_POOL_TIMEOUT)
try:
# ...
except:
# If we hit any problems here, clean up the connection.
# Then, reraise so that we can handle the actual exception.
low_conn.close()
raise
Интересно, что соединение не может быть закрыто, если ошибок нет, в зависимости от того, как вы настроили объединение пулов для urllib3
. В случае успешного выполнения соединение возвращается в пул соединений (хотя я не могу найти вызов _put_conn
в источнике requests
для send
, что может быть ошибкой в рабочем потоке).