如何防止clj-http.client请求卡死

关于timeout参数

clj-http.client的请求(如GET/POST/PUT/DELTE/OPTION等)均支持超时参数配置,各超时参数的含义如下:

:connection-timeout 5000 ;; 与服务建立连接的超时时间
:socket-timeout 5000 ;; 两个数据包之间的最长等待时间
:connection-request-timeout 5000 ;; 从ConnectionManager获取连接的最长超时时间

:conn-request-timeout 5000 ;; 同connection-request-timeout,已不建议使用
:conn-timeout 5000 ;; 同connection-timeout,已不建议使用

可见我们通常只使用前三个参数即可。

参数值设为0时,表示不限制对应的超时时间;设为负数时表示使用系统默认超时时间。

由于系统默认超时时间通常长达几分钟或更长,对于大多数应用可能太长。建议使用clj-http.client发送HTTP请求时都带上以上参数,避免程序假死。

若使用连接池,则应该通过连接池创建函数来配置超时。连接池函数clj-http.client/with-connection-poolclj-http.client/with-async-connection-pool的文档已经有比较详细的说明了,这里就不作赘述了。

重试策略:retry-handler

即使已经配置好以上的超时参数,你可能还会发现http请求卡住,这很可能是因为IO异常导致请求被不停重试。

可以通过设置:retry-handler传入IO异常处理函数,定制重试策略。其中的try-count即为已经重试的次数,此函数返回false即停止重试HTTP请求。

例子

下面是下载图片的一个完整示例:

(require '[clj-http.client :as client])
(require '[clojure.java.io :as io])

(def client-opts {:socket-timeout 5000
                  :connection-timeout 5000
                  :connection-request-timeout 5000
                  :retry-handler (fn [ex try-count http-context]
                                   (t/warn "ignore" ex)
                                   false)})

(let [url "https://pics4.baidu.com/feed/9f2f070828381f305d89a4783526e20c6f06f07f.jpeg?token=7b7cac935fe474bbf2bdfccc3395d5ca&s=DB300FC0C407CAEC2638E5750300D032"
      {:keys [body status]} (client/get url client-opts)]
  (when (= 200 status)
    (io/copy body "a.jpg")))
Comment