设置socket超时是否取消初始请求

Does setting socket timeout cancel the initial request

我有一个请求只能运行一次。有时,请求花费的时间比应有的时间长得多。

如果我要设置一个默认的套接字超时值(使用 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)

这不太可能像您希望的那样工作。 HTTP POST(与任何其他 HTTP 请求一样)是通过向 Web 服务器发送命令,然后接收响应来实现的。 python requests 库为您封装了很多乏味的部分,但核心是,它将执行一个套接字 send,然后是一个套接字 recv(它根据数据的大小,当然可能需要多个 sendrecv

现在,如果您最初能够连接到 Web 服务器(同样,这由 requests 库为您处理,但通常只需要几毫秒),那么很有可能您的 POST 请求中的数据早已发送。 (如果您发送的数据是兆字节长,则可能只发送了部分数据,但如果相当短,则几乎可以肯定已全部发送。)

这反过来意味着服务器很可能已经收到您的整个请求并正在处理它,或者已经将您的请求排入队列以最终处理它。在任何一种情况下,即使您通过 recv 超时来断开与服务器的连接,服务器也不太可能真正注意到这一点,直到它到达发送响应的执行点根据您的要求。到那时,它可能已经完成了它要做的事情。

换句话说,您的套接字超时不会应用于“HTTP 请求”——它适用于底层套接字操作——而且几乎肯定适用于尾端的 recv 部分.仅仅断开套接字连接并不会取消 HTTP 请求。

如果不设计与 HTTP 服务器密切合作的事务协议,就没有可靠的方法来做你想做的事。

你可以做一些(仍然与 HTTP 服务器合作)可以做一些近似于它的事情:

  1. 创建唯一 ID(UUID 等)
  2. 向包含该 UUID 以及其他帐户信息(名称、密码等)的服务器发送请求
  3. 服务器只有在尚未创建具有相同唯一 ID 的帐户时才会创建该帐户。

这样,您可以多次请求该操作,但知道它实际上只会执行一次。如果要求第二次执行相同的操作,服务器将简单地响应“是的,已经这样做了”。