Отменяет ли установка тайм-аута сокета первоначальный запрос

У меня есть запрос, который можно выполнить только один раз. Иногда запрос занимает намного больше времени, чем следовало бы.

Если бы я установил значение тайм-аута сокета по умолчанию (используя socket.setdefaulttimeout(5)), и это заняло больше 5 секунд, будет ли исходный запрос отменен, чтобы можно было безопасно повторить попытку (см. пример кода ниже)?

Если нет, как лучше всего отменить исходный запрос и повторить его еще раз, убедившись, что он никогда не запускается более одного раза.

      import socket
from googleapiclient.discovery import build
from tenacity import retry, stop_after_attempt, wait_fixed, retry_if_exception_type

@retry(
    retry=retry_if_exception_type(socket.timeout),
    wait=wait_fixed(4),
    stop=stop_after_attempt(3)
)
def create_file_once_only(creds, body):
    service = build('drive', 'v3', credentials=creds)
    file = service.files().create(body=body, fields='id').execute()

socket.setdefaulttimeout(5)
create_file_once_only(creds, body)

1 ответ

Маловероятно, что это может работать так, как вы надеетесь. HTTP POST (как и любой другой HTTP-запрос) реализуется путем отправки команды на веб-сервер, а затем получения ответа. Библиотека python инкапсулирует для вас множество утомительных частей, но по сути она будет делать сокет, за которым следует сокет (конечно, может потребоваться более одного send или в зависимости от размера данных).

Теперь, если вы изначально смогли подключиться к веб-серверу (опять же, об этом позаботится requestsбиблиотека, но обычно занимает всего несколько миллисекунд), то весьма вероятно, что данные в вашем запросе POST уже давно отправлены. (Если данные, которые вы отправляете, имеют размер в мегабайтах, возможно, они были отправлены только частично, но если они достаточно короткие, они почти наверняка отправлены полностью.)

Это, в свою очередь, означает, что, по всей вероятности, сервер получил весь ваш запрос и работает над ним или поставил ваш запрос в очередь, чтобы в конечном итоге обработать его. В любом случае, даже если вы разорвете соединение с сервером из-за тайм-аута, маловероятно, что сервер вообще заметит это, пока не дойдет до той точки в своем исполнении, где он будет отправлять свой ответ на ваш запрос. К этому моменту он, вероятно, закончил делать то, что собирался делать.

Другими словами, тайм-аут вашего сокета не будет применяться к «HTTP-запросу» - вместо этого он применяется к базовым операциям сокета - и почти наверняка к recvчасть на хвостовой части. И просто разрыв соединения с сокетом не отменяет HTTP-запрос.

Нет надежного способа делать то, что вы хотите, без разработки протокола транзакций с тесным взаимодействием с HTTP-сервером.

Вы могли бы сделать что-то (при сотрудничестве HTTP-сервера), что могло бы сделать что-то похожее на это:

  1. Создайте уникальный идентификатор (UUID или подобное)
  2. Отправьте запрос на сервер, который содержит этот UUID вместе с другой информацией об учетной записи (имя, пароль и т. Д.)
  3. Затем сервер создает учетную запись только в том случае, если он еще не создал учетную запись с таким же уникальным идентификатором.

Таким образом, вы можете запрашивать операцию несколько раз, но знайте, что на самом деле она будет реализована только один раз. Если вас попросят выполнить ту же операцию второй раз, сервер просто ответит «да, это уже было сделано».

Другие вопросы по тегам