-
Notifications
You must be signed in to change notification settings - Fork 239
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support cancellation during client connection establishment #721
base: master
Are you sure you want to change the base?
Changes from all commits
9a66ceb
8e1edd9
ad58861
568847c
d14b846
d2233c6
ef28e80
11e9eef
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
(ns aleph.util | ||
(:require [manifold.deferred :as d])) | ||
|
||
(defn on-error | ||
[d f] | ||
(d/on-realized d identity f)) | ||
Comment on lines
+4
to
+6
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK for now, but this should be in Manifold |
||
|
||
(defn propagate-error | ||
"Registers an error callback with source which will attempt to propagate the error to destination. | ||
|
||
If the error was propagated (i.e. destination wasn't yet realized), on-propagate is invoked with | ||
the error value. | ||
|
||
Returns source." | ||
([source destination] | ||
(propagate-error source destination identity)) | ||
([source destination on-propagate] | ||
(on-error source (fn [e] | ||
(when (d/error! destination e) | ||
(on-propagate e)))))) | ||
Comment on lines
+8
to
+20
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,7 +7,7 @@ | |
[aleph.resource-leak-detector] | ||
[aleph.ssl :as test-ssl] | ||
[aleph.tcp :as tcp] | ||
[aleph.testutils :refer [str=]] | ||
[aleph.testutils :refer [passive-tcp-server str=]] | ||
[clj-commons.byte-streams :as bs] | ||
[clojure.java.io :as io] | ||
[clojure.string :as str] | ||
|
@@ -1451,18 +1451,50 @@ | |
(is (instance? IllegalArgumentException result)) | ||
(is (= "use-h2c? may only be true when HTTP/2 is enabled." (ex-message result)))))) | ||
|
||
(deftest test-request-cancellation-during-connection-acquisition | ||
(let [starved-pool (http/connection-pool | ||
{:total-connections 0})] | ||
(try | ||
(let [rsp (http-get "/" {:pool starved-pool | ||
:pool-timeout 500})] | ||
(http/cancel-request! rsp) | ||
(is (thrown? RequestCancellationException (deref rsp 0 :timeout)))) | ||
(finally | ||
(.shutdown ^Pool starved-pool))))) | ||
|
||
(deftest test-request-cancellation-during-connection-establishment | ||
(let [connect-client @#'aleph.netty/connect-client | ||
connect-future (promise)] | ||
(with-redefs [aleph.netty/connect-client (fn [& args] | ||
(let [fut (apply connect-client args)] | ||
(deliver connect-future fut) | ||
fut))] | ||
(with-server (passive-tcp-server port) | ||
(let [rsp (http-get "/")] | ||
(is (some? (deref connect-future 1000 nil))) | ||
(http/cancel-request! rsp) | ||
(is (thrown? RequestCancellationException (deref rsp 1000 :timeout))) | ||
(some-> @connect-future (.await 2000 TimeUnit/MILLISECONDS)) | ||
(is (some-> @connect-future .isSuccess false?)) | ||
(is (some-> @connect-future .isDone)) | ||
(is (some-> @connect-future .isCancelled))))))) | ||
|
||
(deftest test-in-flight-request-cancellation | ||
(let [conn-established (promise) | ||
conn-closed (promise)] | ||
(let [conn-established (atom nil) | ||
conn-closed (atom nil)] | ||
(with-raw-handler (fn [req] | ||
(deliver conn-established true) | ||
(deliver @conn-established true) | ||
(s/on-closed (:body req) | ||
(fn [] | ||
(deliver conn-closed true)))) | ||
(deliver @conn-closed true)))) | ||
;; NOTE: The atom indirection here is needed because `with-raw-handler` will run the body | ||
;; twice (for HTTP1 and HTTP2), so we need a new promise for each run. | ||
(reset! conn-established (promise)) | ||
(reset! conn-closed (promise)) | ||
(let [rsp (http-get "/")] | ||
(is (= true (deref conn-established 1000 :timeout))) | ||
(is (= true (deref @conn-established 1000 :timeout))) | ||
(http/cancel-request! rsp) | ||
(is (= true (deref conn-closed 1000 :timeout))) | ||
(is (= true (deref @conn-closed 1000 :timeout))) | ||
Comment on lines
-1463
to
+1497
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
(is (thrown? RequestCancellationException (deref rsp 1000 :timeout))))))) | ||
|
||
(deftest ^:leak test-leak-in-raw-stream-handler | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it should be documented why you would use this over chain or on-realized.