f859bd907a
This commit moves each close call made on a `CloseableHttpAsyncClient` from the thread on which the request callback is made over to a different thread in order to avoid a deadlock. Previously, the client close call was made in the context of thread from which the callback was invoked. The Apache HTTP async client library makes these calls from one of its i/o reactor threads. In the case of a "failed" request, e.g., failure to make the client connection, this call occurs in the context of the primary i/o reactor thread. The client close call does an indefinite join on the primary i/o reactor thread and, therefore, this call causes a deadlock. The client never closes and all resources associated with it - threads, file descriptors, etc. - remain open until the process is shutdown. This commit introduces a new class, `AsyncClose`, which manages a small, fixed size thread pool from which client close calls can be executed. The `async` Clojure and `JavaClient` APIs were updated to use `AsyncClose` whenever a client needs to be closed from a callback.
22 lines
826 B
Clojure
22 lines
826 B
Clojure
(ns com.puppetlabs.http.client.impl.async-close-test
|
|
(:import (java.io Closeable)
|
|
(com.puppetlabs.http.client.impl AsyncClose))
|
|
(:require [clojure.test :refer :all]))
|
|
|
|
(defn closeable
|
|
[closeable-promise]
|
|
(reify Closeable
|
|
(close [this]
|
|
(deliver closeable-promise (Thread/currentThread)))))
|
|
|
|
(deftest closeable-asynchronously-closed
|
|
(testing "Close called asynchronously on a closeable"
|
|
(let [closeable-promise (promise)
|
|
closeable (closeable closeable-promise)]
|
|
(AsyncClose/close closeable)
|
|
(is @closeable-promise "Promise realized as nil")
|
|
(is (instance? Thread @closeable-promise) "Thread not delivered")
|
|
(is (not (identical? (Thread/currentThread) @closeable-promise))
|
|
"Closeable closed from originating thread, not asynchronously"))))
|
|
|
|
|