更优雅的方法来处理core.async中的错误和超时?

时间:2014-10-21 12:46:46

标签: clojure core.async

当然我想用core.async将各种请求包装到外部服务,同时仍然通过一些chan返回这些操作的结果。

我想要处理抛出的异常和超时(即操作需要比预期更长的时间才能返回,或者能够为同一任务选择各种服务,但使用不同的方法或服务质量。

显示能够处理错误,超时和正确返回结果的示例的最小可行示例似乎是:

(require '[clojure.core.async :refer [chan go timeout <! >! alt!]])

(def logchan (chan 1))

(go (loop []
      (when-let [v (<! logchan)]
        (println v)
        (recur))))

(dotimes [_ 10] 
  (go 
    (let [result-chan  (chan 1)
          error-chan   (chan 1)
          timeout-chan (timeout 100)]
      (go
        (try 
          (do (<! (timeout (rand-int 200)))
              (>! result-chan (/ 1 (rand-int 2))))
          (catch Exception e (>! error-chan :error))))
      (>! logchan (alt! [result-chan error-chan timeout-chan] 
                    ([v] (if v v :timeout)))))))

此代码打印类似

1
:error
1
:error
:error
:timeout
:error
:timeout
:timeout

这不是很优雅。我特别不喜欢返回:error:timeout的方式。 nil - 签入alt!显然不是我想要的。

是否有更好的方法来实现返回结果的三个目标,保护免受长时间超时处理错误?语法很好(上面的大部分内容都是为了引发这三个错误)。

2 个答案:

答案 0 :(得分:5)

core.async chan - 函数具有ex-handler,因此可以使用以下构造

(chan buf-or-n xform ex-handler)

其中ex-handler是一个获得异常的单参数函数。当函数返回nil时,它不会被放在通道上,否则函数有机会将异常转换为可用于相关数据的事物。

答案 1 :(得分:2)

将输出放在一个通道中,错误和结果。

定义记录(地图)以查找错误,例如

(defrecord SomeError [cause context etc...])

这样,错误将包含相关信息。

验证消费者的输出

(if-not (instance? SomeError result) ...)

没有人正确的&#39;方式,你可以使用pub / sub用于相同的目的,传入一个错误-chan或创建几个和async /将它们合并在一起。