【问题标题】:More elegant way to handle error and timeouts in core.async?更优雅的方式来处理 core.async 中的错误和超时?
【发布时间】:2014-10-21 12:46:46
【问题描述】:

当然,我想用 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-check in alt! 显然也不是我想要的。

有没有更好的方法来实现返回结果防止长时间超时处理错误这三个目标?语法还算可以(上面的大部分内容确实是为了挑起这三个错误)。

【问题讨论】:

    标签: clojure core.async


    【解决方案1】:

    core.async chan-function 有 ex-handler,所以下面的构造是可能的

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

    其中ex-handler 是一个获取异常的单参数函数。当函数返回 nil 时,不会将其放在通道上,否则函数有机会将异常转换为对相关数据可行的东西。

    【讨论】:

    • 哦,顺便说一句,这在pipeline 命令中也可用!
    【解决方案2】:

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

    为错误定义记录(映射),例如

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

    这样错误将保存相关信息。

    验证消费者的输出

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

    没有一种“正确”的方式,您可以将 pub/sub 用于相同目的,传入一个错误通道或创建多个并将它们异步/合并在一起。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-06-06
      • 1970-01-01
      • 1970-01-01
      • 2015-02-05
      • 2011-12-09
      • 1970-01-01
      • 1970-01-01
      • 2015-04-10
      相关资源
      最近更新 更多