File tree Expand file tree Collapse file tree 8 files changed +187
-10
lines changed Expand file tree Collapse file tree 8 files changed +187
-10
lines changed Original file line number Diff line number Diff line change 5
5
java.util.concurrent.CompletionException
6
6
java.util.function.Function)))
7
7
8
+ #?(:clj
9
+ (defn -forward-bindings [f]
10
+ (fn [ctx]
11
+ (with-bindings (or (:bindings ctx) {})
12
+ ((bound-fn* f) ctx)))))
13
+
8
14
(defprotocol AsyncContext
9
15
(async? [t])
10
16
(continue [t f])
21
27
(extend-protocol AsyncContext
22
28
Object
23
29
(async? [_] false )
30
+ ; Given the implementation of enter/leave,
31
+ ; `continue` won't be called, and therefore,
32
+ ; the function call does not need to be bound
24
33
(continue [t f] (f t))
25
34
(await [t] t)))
26
35
27
36
#?(:cljs
28
37
(extend-protocol AsyncContext
29
38
default
30
39
(async? [_] false )
40
+ ; Given the implementation of enter/leave,
41
+ ; `continue` won't be called, and therefore,
42
+ ; the function call does not need to be bound
31
43
(continue [t f] (f t))))
32
44
33
45
#?(:clj
34
46
(extend-protocol AsyncContext
35
47
clojure.lang.IDeref
36
48
(async? [_] true )
37
- (continue [c f] (future (f @c)))
49
+ (continue [c f]
50
+ (cond
51
+ ; Make sure there is
52
+ (map? @c)
53
+ (with-bindings (or (:bindings @c) {})
54
+ (future ((bound-fn* f) @c)))
55
+ :else
56
+ (future (f @c))))
38
57
(catch [c f] (future (let [c @c]
39
58
(if (exception? c) (f c) c))))
40
59
(await [c] @c)))
44
63
CompletionStage
45
64
(async? [_] true )
46
65
(continue [this f]
66
+ ; Given the "context" is a completion stage, there isn't
67
+ ; a means
47
68
(.thenApply ^CompletionStage this
48
69
^Function (->FunctionWrapper f)))
49
70
Original file line number Diff line number Diff line change 9
9
#?(:clj clojure.core.async.impl.protocols.Channel
10
10
:cljs cljs.core.async.impl.channels/ManyToManyChannel)
11
11
(async? [_] true )
12
- (continue [c f] (go (f (cca/<! c))))
12
+ #?(:clj (continue [c f]
13
+ (let [f' (sa/-forward-bindings f)]
14
+ (go
15
+ (f' (cca/<! c)))))
16
+ :cljs (continue [c f] (go (f (cca/<! c)))))
13
17
(catch [c f] (go (let [c (cca/<! c)]
14
18
(if (exception? c) (f c) c))))
15
19
#?(:clj (await [c] (<!! c))))
Original file line number Diff line number Diff line change 2
2
(:require [sieppari.async :as sa]
3
3
[manifold.deferred :as d]))
4
4
5
+ ; chain'-, as is being used here, is chain'-/3
6
+ ; chain'-/3, at the time of writing, has an arglist of:
7
+ ; [d x f]
8
+ ; where:
9
+ ; - `d` is a non-realized manifold deferred value, or nil
10
+ ; to signal a deferred should be returned/provided
11
+ ; - `x` is either a deferred or a value. If it is a deferred,
12
+ ; then the deferred is recurively realized until a non-deferred value
13
+ ; is yeilded.
14
+ ; - `f` is a function applied to the unwrapped value `x`, before being either realized
15
+ ; into `d` or being returned as a sucess or error deferred, depending on the result
16
+ ; of `(f x)`.
5
17
(extend-protocol sa/AsyncContext
6
18
manifold.deferred.Deferred
7
19
(async? [_] true )
8
- (continue [d f] (d/chain'- nil d f))
9
- (catch [d f] (d/catch' d f))
20
+ (continue [d f]
21
+ (d/chain'- nil d (sa/-forward-bindings f)))
22
+ (catch [d f]
23
+ (d/catch' d (sa/-forward-bindings f)))
10
24
(await [d] (deref d))
11
25
12
26
manifold.deferred.ErrorDeferred
13
27
(async? [_] true )
14
- (continue [d f] (d/chain'- nil d f))
15
- (catch [d f] (d/catch' d f))
28
+ (continue [d f]
29
+ (d/chain'- nil d (sa/-forward-bindings f)))
30
+ (catch [d f]
31
+ (d/catch' d (sa/-forward-bindings f)))
16
32
(await [d] (deref d)))
Original file line number Diff line number Diff line change 14
14
c /Context
15
15
(context? [_] true ))
16
16
17
+
17
18
(defn- -try [ctx f]
18
19
(if f
19
20
(try
20
- (let [ctx* (f ctx)]
21
+ (let [ctx* #?(:clj (with-bindings (or (:bindings ctx) {})
22
+ ; Given the various async
23
+ ; executors may exec on different threads,
24
+ ; the fn must be bound in order to preserve
25
+ ; bindings
26
+ ((bound-fn* f) ctx))
27
+ :cljs (f ctx))]
21
28
(if (a/async? ctx*)
22
29
(a/catch ctx* (fn [e] (assoc ctx :error e)))
23
30
ctx*))
79
86
(callback result))))
80
87
81
88
(defn- remove-context-keys [ctx]
82
- (dissoc ctx :error :queue :stack ))
89
+ (dissoc ctx :bindings : error :queue :stack ))
83
90
84
91
; ;
85
92
; ; Public API:
Original file line number Diff line number Diff line change 246
246
[:error :c ]
247
247
[:error :b ]
248
248
[:leave :a ]])))
249
+
250
+ (def ^:dynamic *boundv* 41 )
251
+
252
+ (defn bindings-handler [_]
253
+ (is (= 43 *boundv*))
254
+ (go
255
+ *boundv*))
256
+
257
+ (def bindings-chain
258
+ [{:enter (fn [ctx]
259
+ (go
260
+ (assoc ctx
261
+ :bindings
262
+ {#'*boundv* 42 })))
263
+ :leave (fn [ctx]
264
+ (go
265
+ (is (= 42 *boundv*))
266
+ ctx))}
267
+ {:enter (fn [ctx]
268
+ (is (= 42 *boundv*)
269
+ " In interceptor failed" )
270
+ (go
271
+ (update-in ctx [:bindings #'*boundv*] inc)))
272
+ :leave (fn [ctx]
273
+ (go
274
+ (update-in ctx [:bindings #'*boundv*] dec)))}
275
+
276
+ bindings-handler])
277
+
278
+ (deftest async-bindings-test
279
+ (fact " bindings are conveyed across interceptor chain"
280
+ (sc/execute bindings-chain {}) => 43 ))
281
+
Original file line number Diff line number Diff line change 6
6
[clojure.string :as str]))
7
7
8
8
; ;
9
- ; ; Following tests use a test-chain that has some interceptors
10
- ; ; that fail on each stage function (enter, leave, error). The
9
+ ; ; Following tests use a test-chain that has some interceptors that fail on each stage function (enter, leave, error). The
11
10
; ; idea is that the tests override the expected stage functions
12
11
; ; with test specific function. This ensures that no unexpected
13
12
; ; stage functions are called.
269
268
[:leave :x ]
270
269
[:leave :a ]]))
271
270
271
+
272
+ (def ^:dynamic *boundv* 41 )
273
+
274
+ (defn bindings-handler [_]
275
+ (is (= 42 *boundv*))
276
+ *boundv*)
277
+
278
+ (def bindings-chain
279
+ [{:enter (fn [ctx] (assoc ctx
280
+ :bindings
281
+ {#'*boundv* 42 }))}
282
+ {:enter (fn [ctx]
283
+ (is (= 42 *boundv*))
284
+ ctx)}
285
+ bindings-handler])
286
+
287
+ (deftest use-bindings-test
288
+ (fact " bindings are conveyed across interceptor chain"
289
+ (s/execute bindings-chain {}) => 42 ))
290
+
272
291
; TODO: figure out how enqueue should work? Should enqueue add interceptors just
273
292
; before the handler?
274
293
#_(deftest enqueue-interceptor-test
Original file line number Diff line number Diff line change 228
228
[:error :c ]
229
229
[:error :b ]
230
230
[:leave :a ]])))
231
+
232
+ (def ^:dynamic *boundv* 41 )
233
+
234
+ (defn bindings-handler [_]
235
+ (is (= 43 *boundv*))
236
+ (d/chain
237
+ nil
238
+ (fn [_]
239
+ *boundv*)))
240
+
241
+ (def bindings-chain
242
+ [{:enter (fn [ctx]
243
+ (d/future
244
+ (assoc ctx
245
+ :bindings
246
+ {#'*boundv* 42 })))
247
+ :leave (fn [ctx]
248
+ (d/chain
249
+ ctx
250
+ (fn [ctx']
251
+ (is (= 42 *boundv*))
252
+ ctx')))}
253
+ {:enter (fn [ctx]
254
+ (is (= 42 *boundv*)
255
+ " In interceptor failed" )
256
+ (d/chain
257
+ ctx
258
+ #(update-in
259
+ %
260
+ [:bindings #'*boundv*] inc)))
261
+ :leave (fn [ctx]
262
+ (d/chain
263
+ ctx
264
+ #(update-in
265
+ %
266
+ [:bindings #'*boundv*] dec)))}
267
+ bindings-handler])
268
+
269
+ (deftest async-bindings-test
270
+ (fact " bindings are conveyed across interceptor chain"
271
+ (sc/execute bindings-chain {}) => 43 ))
272
+
Original file line number Diff line number Diff line change 228
228
[:error :c ]
229
229
[:error :b ]
230
230
[:leave :a ]])))
231
+
232
+ (def ^:dynamic *boundv* 41 )
233
+
234
+ (defn bindings-handler [_]
235
+ (is (= 43 *boundv*))
236
+ (p/resolved
237
+ *boundv*))
238
+
239
+ (def bindings-chain
240
+ [{:enter (fn [ctx]
241
+ (p/resolved
242
+ (assoc ctx
243
+ :bindings
244
+ {#'*boundv* 42 })))
245
+ :leave (fn [ctx]
246
+ (is (= 42 *boundv*))
247
+ ctx)}
248
+ {:enter (fn [ctx]
249
+ (is (= 42 *boundv*))
250
+ (-> ctx
251
+ (update-in [:bindings #'*boundv*]
252
+ inc)
253
+ (p/resolved )))
254
+ :leave (fn [ctx]
255
+ (is (= 43 *boundv*))
256
+ (-> ctx
257
+ (update-in [:bindings #'*boundv*]
258
+ dec)
259
+ (p/resolved )))}
260
+ bindings-handler])
261
+
262
+ (deftest async-bindings-test
263
+ (fact " bindings are conveyed across interceptor chain"
264
+ (sc/execute bindings-chain {}) => 43 ))
265
+
You can’t perform that action at this time.
0 commit comments